package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;

import com.livestocksolutions.util.BovineList;
import com.livestocksolutions.util.Comparators;
import com.livestocksolutions.util.DecimalDocumentFilter;
import com.livestocksolutions.util.JDatePickerDate;
import com.livestocksolutions.util.Table;

import com.livestocksolutions.Acquisition;
import com.livestocksolutions.Bovine;
import com.livestocksolutions.Bull;
import com.livestocksolutions.Business;
import com.livestocksolutions.CattleBreed;
import com.livestocksolutions.Cow;
import com.livestocksolutions.Deacquisition;
import com.livestocksolutions.Eartag;
import com.livestocksolutions.Feed;
import com.livestocksolutions.FeedHistory;
import com.livestocksolutions.Group;
import com.livestocksolutions.Join;
import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.MedicalHistory;
import com.livestocksolutions.Medicine;
import com.livestocksolutions.MedicineHistory;
import com.livestocksolutions.Mob;
import com.livestocksolutions.Observation;
import com.livestocksolutions.Owner;
import com.livestocksolutions.Weight;
import com.livestocksolutions.util.UsableItemList;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

/**
 * Display details relating to any Bovine, or a particular Bovine.
 * @author Ken DeVries
 * @author Adam Parr
 * 
 * @.modified 19 March 2013
 */
public class BovinePanel extends JPanel implements TabbedInterface {
	private static final long serialVersionUID = 1L;

	/**
	 * The initial view for this tab.
	 * Shows all Cattle that are in the system.
	 */
	public static final int CATTLE_LIST = 0;
	/**
	 * To create a new Bovine.
	 */
	public static final int VIEW_NEW_BOVINE=1;
	/**
	 * To view a Bovines details.
	 */
	public static final int VIEW=2;
	/**
	 * The default View when selecting a Bovine to show in detail.
	 * Shows Details of the selected Bovine and also any Observations for that Bovine.
	 */
	public static final int VIEW_OBSERVATION = 3;
	/**
	 * Shows Details of the selected Bovine and also any Offspring for that Bovine.
	 */
	public static final int VIEW_OFFSPRING = 4;
	/**
	 * Shows Details of the selected Bovine and also any Joinings for that Bovine.
	 */
	public static final int VIEW_JOINING = 5;
	/**
	 * Shows Details of the selected Bovine and also any Medicines for that Bovine.
	 */
	public static final int VIEW_MEDICINES = 6;
	/**
	 * Shows Details of the selected Bovine and also any Vet Visits for that Bovine.
	 */
	public static final int VIEW_MEDICALS = 7;
	/**
	 * Shows Details of the selected Bovine and also any Feed given to that Bovine.
	 */
	public static final int VIEW_FEEDS = 8;
	/**
	 * Shows Details of the selected Bovine and also any Weights for that Bovine.
	 */
	public static final int VIEW_WEIGHINGS = 9;
	/**
	 * Shows Details of the selected Bovine and also any Groups the Bovine is in.
	 */
	public static final int VIEW_GROUPS = 10;
	/**
	 * A view that is not static.
	 */
	public static final int VIEW_OTHER = 99;
	
	/**
	 * Determine if the editable details of a Bovine is editable.
	 */
	protected boolean edit = false;
	
	/**
	 * The current view.
	 * 
	 * @see #CATTLE_LIST
	 * @see #VIEW_NEW_BOVINE
	 * @see #VIEW
	 * @see #VIEW_OBSERVATION
	 * @see #VIEW_OFFSPRING
	 * @see #VIEW_JOINING
	 * @see #VIEW_MEDICINES
	 * @see #VIEW_MEDICALS
	 * @see #VIEW_FEEDS
	 * @see #VIEW_WEIGHINGS
	 * @see #VIEW_OTHER
	 */
	protected int viewing = -1;
	
	/**
	 * The ID of the Bovine we are Viewing.
	 */
	protected long bovineViewID = 0;
	
	/**
	 * The length of the NLIS id to be accepted
	 */
	public static final int nlisIDLength = 16;
	/**
	 * The length of the RF id to be accepted
	 */
	public static final int rfIDLength = 16;
	
	protected final JPanel panel = new JPanel();
	protected final JPanel search = new JPanel();
	/**
	 * The Panel where the innerlist for a particular item will rest.
	 */
	protected JTabbedPane jisp = new JTabbedPane();
	protected JPanel observationsListPanel = new JPanel();
	protected JPanel offspringListPanel = new JPanel();
	protected JPanel weighingsListPanel = new JPanel();
	protected JPanel groupsListPanel = new JPanel();
	protected JPanel medicinesListPanel = new JPanel();
	protected JPanel vetVisitsListPanel = new JPanel();
	protected JPanel feedsListPanel = new JPanel();
	protected JPanel joiningListPanel = new JPanel();
	
	private JTextField searchField = new JTextField();
	private JButton searchClearBtn = new JButton("Clear Search");
	
	private JTextField txtVisualID = new JTextField("-1");
	private JTextField txtNlisID = new JTextField();
	private JTextField txtRFID = new JTextField();
	private JDatePickerDate txtDOB = JDatePickerDate.createJDatePicker();
	private JDatePickerDate txtAcquireDate =JDatePickerDate.createJDatePicker();
	private JTextField txtAcquirePrice = new JTextField();
	private JDatePickerDate txtDeacquireDate = JDatePickerDate.createJDatePicker();
	private JTextField sellPrice = new JTextField();
	private JComboBox lstGender = new JComboBox();
	private JComboBox lstMob = new JComboBox();
	private JComboBox lstBreed = new JComboBox();
	private JComboBox lstAcquireMethod = new JComboBox();
	private JComboBox lstPreviousOwner = new JComboBox();
	private JComboBox lstDeacquireMethod = new JComboBox();
	private JComboBox lstNewOwner = new JComboBox();
	private JComboBox lstDame = new JComboBox();
	private JComboBox lstSire = new JComboBox();
	
	/**
	 * This can be checked to see if this animal will become inactive
	 * if disabled, then the button has been clicked, else it has not.
	 */
	private JButton btnSetInactive;
	
	/**
	 * The list of Offspring to add to the current Bovine.
	 */
	private ArrayList<Bovine> bovineOffspringAddList = new ArrayList<Bovine>();
	/**
	 * The list of Groups to add the current Bovine to.
	 */
	private ArrayList<Group> bovineGroupAddList = new ArrayList<Group>();
	
	protected ArrayList<BovineList<Bull>> bullList = new ArrayList<BovineList<Bull>>();
	protected ArrayList<BovineList<Cow>> cowList = new ArrayList<BovineList<Cow>>();
	protected Mob[] mobList = new Mob[]{};
	
	/**
	 * Sort the list by Name tag.
	 */
	protected static final int LIST_ORDER_NAME 		= 0;
	/**
	 * Sort the list by Mob Location tag.
	 * Only available for use with Mob Objects.
	 */
	protected static final int LIST_ORDER_LOCATION 	= 1;
	/**
	 * Sort the list by the number of members.
	 */
	protected static final int LIST_ORDER_COUNT		= 2;
	/**
	 * Sort the observation list by Creation Date.
	 */
	protected static final int LIST_ORDER_DATE 		= 1;
	/**
	 * Sort the observation list by using the Priority.
	 */
	protected static final int LIST_ORDER_PRIORITY = 0;
	
	/**
	 * Sort the member list by Visual ID tag.
	 */
	protected static final int LIST_ORDER_VISUAL 	= 0;
	/**
	 * Sort the member list by using NLIS ID.
	 */
	protected static final int LIST_ORDER_NLIS 		= 1;
	/**
	 * Sort the member list by using RF ID.
	 */
	protected static final int LIST_ORDER_RF 		= 2;
	/**
	 * Sort the member list by DOB.
	 */
	protected static final int LIST_ORDER_DOB 		= 3;
	/**
	 * Sort the member list by active status.
	 */
	protected static final int LIST_ORDER_ACTIVE	= 4;
	/**
	 * Sort the member list by number of Offspring.
	 */
	protected static final int LIST_ORDER_OFFSPRING = 5;
	/**
	 * Sort the member list by gender.
	 */
	protected static final int LIST_ORDER_GENDER 	= 6;
	
	/**
	 * Sort the joining list by using bull entry date.
	 */
	protected static final int LIST_ORDER_ENTRY 	= 0;
	/**
	 * Sort the joining list by using bull exit date.
	 */
	protected static final int LIST_ORDER_EXIT 		= 1;
	/**
	 * Sort the joining list by using bull visual ID.
	 */
	protected static final int LIST_ORDER_BULL 		= 2;
	/**
	 * Sort the joining list by using number of cows in the join.
	 */
	protected static final int LIST_ORDER_COW_COUNT	= 3;
	
	/**
	 * Sort the UsableItemHistory list by using quantity given.
	 */
	protected static final int LIST_ORDER_QTY		= 2;
	/**
	 * Sort the UsableItemHistory list by using items purchase date.
	 */
	protected static final int LIST_ORDER_PURCHASEDATE= 3;
	/**
	 * Sort MedicalItemHistory list by the cost of the vet visit and medicines.
	 */
	protected static final int LIST_ORDER_COST 		= 0;
	
	/**
	 * The current list order method.
	 * @see #LIST_ORDER_NAME
	 * @see #LIST_ORDER_COUNT
	 */
	protected int orderMobListBy = LIST_ORDER_NAME, orderGroupListBy = LIST_ORDER_NAME;
	/**
	 * The items Observation list order method.
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_PRIORITY
	 */
	protected int orderObservationListBy = LIST_ORDER_DATE;
	/**
	 * The current member list order method.
	 * @see #LIST_ORDER_VISUAL
	 * @see #LIST_ORDER_NLIS
	 * @see #LIST_ORDER_RF
	 * @see #LIST_ORDER_DOB
	 * @see #LIST_ORDER_ACTIVE
	 * @see #LIST_ORDER_OFFSPRING
	 * @see #LIST_ORDER_GENDER
	 */
	protected int orderCattleListBy = LIST_ORDER_VISUAL, orderOffspringListBy = LIST_ORDER_VISUAL;
	
	/**
	 * The current joining list order method.
	 * @see #LIST_ORDER_ENTRY
	 * @see #LIST_ORDER_EXIT
	 * @see #LIST_ORDER_BULL
	 * @see #LIST_ORDER_COW_COUNT
	 */
	protected int orderJoiningListBy = LIST_ORDER_VISUAL;
	
	/**
	 * Order the UsableItem History list.
	 * @see #LIST_ORDER_NAME
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_QTY
	 * @see #LIST_ORDER_PURCHASEDATE
	 */
	protected int orderFeedItemListBy = LIST_ORDER_NAME, orderMedicineItemListBy = LIST_ORDER_NAME;
	
	/**
	 * Order the MedicalItem History list.
	 * @see #LIST_ORDER_DATE
	 * @see #LIST_ORDER_COUNT
	 * @see #LIST_ORDER_COST
	 */
	protected int orderMedicalItemListBy = LIST_ORDER_DATE;
	/**
	 * The sort direction. Ascending : 1, Descending -1;
	 */
	protected int orderMobHighToLow = 1, orderGroupHighToLow = 1, orderObservationHighToLow = 1, orderCattleHighToLow = 1, orderJoiningHighToLow = 1, orderOffspringHighToLow = 1, orderFeedItemHighToLow = 1, orderMedicalItemHighToLow = 1, orderMedicineItemHighToLow = 1;
	
	/**
	 * The search string that the main cattle list will be filtered against.
	 */
	protected String searchFilter = null;
	
	/**
	 * Area where the cattle list will be shown while showing detail for a specific animal. 
	 */
	protected SidePanel list = new SidePanel();
	
	/**
	 * List of cattle to display in the list.
	 */
	protected Bovine[] bList;
	
	/**
	 * Constructor
	 */
	public BovinePanel(){
		JScrollPane jsp = new JScrollPane();
		
		setLayout(new BorderLayout(0, 0));
		jsp.setViewportView(panel);
		jsp.setViewportBorder(BorderFactory.createEmptyBorder());

		add(jsp);
		panel.setLayout(new BorderLayout(10, 10));
		createSearchPane();
		
		lstGender.setModel(new DefaultComboBoxModel(new String[]{Bovine.GENDER,Bull.GENDER,Cow.GENDER}));
		lstAcquireMethod.setModel(new DefaultComboBoxModel(new String[] {"Birth", "Purchase"}));
		lstDeacquireMethod.setModel(new DefaultComboBoxModel(new String[] {"Death", "Sold"}));
		
		((AbstractDocument)txtAcquirePrice.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
		((AbstractDocument)sellPrice.getDocument()).setDocumentFilter(new DecimalDocumentFilter());

		AdjustmentListener al = new AdjustmentListener(){
			@Override
			public void adjustmentValueChanged(AdjustmentEvent evt) {
				panel.repaint();
			}
		};
		jsp.getHorizontalScrollBar().addAdjustmentListener(al);
		jsp.getVerticalScrollBar().addAdjustmentListener(al);
	}
	
	@Override
	public void displayPanel(){
		int panel = viewing;
		if(viewing==CATTLE_LIST) {
			viewing=-1;
			panel = CATTLE_LIST;
		}
		displayPanel(panel);
	}
	
	/**
	 * @see #CATTLE_LIST
	 * @see #VIEW_NEW_BOVINE
	 * @see #VIEW
	 * @see #VIEW_OBSERVATION
	 * @see #VIEW_OFFSPRING
	 * @see #VIEW_JOINING
	 * @see #VIEW_MEDICINES
	 * @see #VIEW_MEDICALS
	 * @see #VIEW_FEEDS
	 * @see #VIEW_WEIGHINGS
	 * @see #VIEW_OTHER
	 */
	@Override
	public void displayPanel(int panel){
		switch(panel){
			case CATTLE_LIST:
				if(viewing!=CATTLE_LIST){
					createHomePanel();
				}
				break;
			case VIEW_NEW_BOVINE:
				if(viewing!=VIEW_NEW_BOVINE){
					createBovinePanel(-1);
				}
				break;
			case VIEW:
			case VIEW_OBSERVATION:
			case VIEW_OFFSPRING:
			case VIEW_JOINING:
			case VIEW_MEDICINES:
			case VIEW_MEDICALS:
			case VIEW_FEEDS:
			case VIEW_WEIGHINGS:
			case VIEW_GROUPS:
			case VIEW_OTHER:
				createBovinePanel(bovineViewID);
				break;
			default :
				createHomePanel();
		}
	}
	
	/**
	 * Create the search section of this page
	 */
	private void createSearchPane(){
		search.removeAll();
		search.setLayout(new BorderLayout(0, 0));
		
		JPanel label = new JPanel();
		label.add(new JLabel("Search for Cattle"));
		search.add(label, BorderLayout.NORTH);
		
		JPanel buttonAndText = new JPanel();
		buttonAndText.setLayout(new BoxLayout(buttonAndText, BoxLayout.X_AXIS));
		search.add(buttonAndText, BorderLayout.CENTER);

		searchField.addKeyListener(new KeyListener(){
			@Override public void keyTyped(KeyEvent e) {}
			@Override public void keyPressed(KeyEvent e) {}
			@Override
			public void keyReleased(KeyEvent e) {
				if(e.getKeyCode()==KeyEvent.VK_ENTER){
					createDisplaySearchDetails(searchField.getText());
				}
			}
		});
		
		JButton searchBtn = new JButton("Search");
		searchBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createDisplaySearchDetails(searchField.getText());
			}
		});
		
		searchClearBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				searchField.setText("");
				createDisplaySearchDetails(searchField.getText());
			}
		});
		
		searchClearBtn.setVisible(false);
		buttonAndText.add(searchClearBtn);
		buttonAndText.add(searchField);
		buttonAndText.add(searchBtn);
	}
	
	/**
	 * Conduct a search for a Bovine.
	 * @param searchQuery The String to use to search for any matching Bovines.
	 * @return <tt>true</tt> if search was completed,
	 * <tt>false</tt> otherwise.
	 */
	public boolean createDisplaySearchDetails(String searchQuery){
		searchClearBtn.setVisible(!searchQuery.equals(""));
		searchField.setText(searchQuery);
		searchFilter = searchQuery;
		createHomePanel();
		return true;
	}

	/**
	 * Create the list of Bovine animals to chose from.
	 */
	private void createHomePanel(){
		viewing = CATTLE_LIST;
		
		bovineViewID = 0;
		panel.setLayout(new BorderLayout(0, 0));
		final int VISUAL 	= 0;
		final int NLIS 		= 1;
		final int RF 		= 2;
		final int DOB 		= 3;
		final int GENDER	= 4;
		final int OFFSPRING = 5;
		final int ACTIVE	= 6;
		
		final Table bovinePanel = new Table("Cattle List",false,
			"Visual ID","NLIS","RF ID","DOB","Gender","No. Offspring","Status");
		bovinePanel.setEmptyMessage("There are no cattle to show.");
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				bList = LivestockSolutions.getBovines();
				if(searchFilter!=null){
					ArrayList<Bovine> searchArray = new ArrayList<Bovine>();
					
					for(Bovine b : bList){
						if(b.getEartag().getEartagID().toLowerCase().contains(searchFilter.trim().toLowerCase())
						|| b.getEartag().getNlisID().toLowerCase().contains(searchFilter.trim().toLowerCase())
						|| b.getEartag().getRfID().toLowerCase().contains(searchFilter.trim().toLowerCase())
						||(b.isActive() && (searchFilter.trim().toLowerCase().equals("active") || searchFilter.trim().toLowerCase().equals("!inactive") || searchFilter.trim().toLowerCase().equals("! inactive")))
						||(!b.isActive() && (searchFilter.trim().toLowerCase().equals("inactive") || searchFilter.trim().toLowerCase().equals("!active") || searchFilter.trim().toLowerCase().equals("! active")))
						|| searchFilter.split("-").length>=3 && b.getDob().equals(JDatePickerDate.parse(searchFilter))){
							searchArray.add(b);
						}
					}
					bList = searchArray.toArray(new Bovine[searchArray.size()]);
				}

				Arrays.sort(bList, 
					orderCattleListBy==LIST_ORDER_VISUAL?
						orderCattleHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
					:orderCattleListBy==LIST_ORDER_NLIS?
						orderCattleHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
					:orderCattleListBy==LIST_ORDER_RF?
						orderCattleHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
					:orderCattleListBy==LIST_ORDER_DOB?
						orderCattleHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
					:orderCattleListBy==LIST_ORDER_OFFSPRING?
						orderCattleHighToLow==1?Comparators.bovineNumberOffspringComparator:Collections.reverseOrder(Comparators.bovineNumberOffspringComparator)
					:orderCattleListBy==LIST_ORDER_GENDER?
						orderCattleHighToLow==1?Comparators.bovineComparatorGender:Collections.reverseOrder(Comparators.bovineComparatorGender)
					:orderCattleHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));

				bovinePanel.setHeaderOrderedBy(orderCattleListBy==LIST_ORDER_VISUAL?VISUAL:orderCattleListBy==LIST_ORDER_RF?RF:orderCattleListBy==LIST_ORDER_NLIS?NLIS:orderCattleListBy==LIST_ORDER_DOB?DOB:orderCattleListBy==LIST_ORDER_ACTIVE?ACTIVE:orderCattleListBy==LIST_ORDER_GENDER?GENDER:orderCattleListBy==LIST_ORDER_OFFSPRING?OFFSPRING:VISUAL,orderCattleHighToLow==1);
				bovinePanel.addHeaderMouseListener(VISUAL, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_VISUAL?-1:1);
						orderCattleListBy = LIST_ORDER_VISUAL;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(RF, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_RF?-1:1);
						orderCattleListBy = LIST_ORDER_RF;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(NLIS, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_NLIS?-1:1);
						orderCattleListBy = LIST_ORDER_NLIS;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(DOB, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_DOB?-1:1);
						orderCattleListBy = LIST_ORDER_DOB;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(ACTIVE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_ACTIVE?-1:1);
						orderCattleListBy = LIST_ORDER_ACTIVE;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(OFFSPRING, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_OFFSPRING?-1:1);
						orderCattleListBy = LIST_ORDER_OFFSPRING;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(GENDER, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderCattleHighToLow = orderCattleHighToLow*(orderCattleListBy==LIST_ORDER_GENDER?-1:1);
						orderCattleListBy = LIST_ORDER_GENDER;
						createHomePanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				for(int x=0; x<bList.length; x++){
					bovinePanel.addRow(
						new JLabel(bList[x].getEartag().getEartagID()),
						new JLabel(bList[x].getEartag().getNlisID()),
						new JLabel(bList[x].getEartag().getRfID()),
						new JLabel(bList[x].getDob()!=null?JDatePickerDate.format(bList[x].getDob()):"Unknown"),
						new JLabel(bList[x].getGender()),
						new JLabel(String.valueOf(bList[x].getOffspring().length)),
						new JLabel(bList[x].isActive()?"Active":bList[x].getDeacquisition().getMethod()));
						
					final long id = bList[x].getID();
					bovinePanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							createBovinePanel(id);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		if(getComponent(0)!=search){
			add(search, BorderLayout.NORTH);
		}

		panel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewCattle = new JButton("New Animal");
		btnNewCattle.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createBovinePanel(-1L);
			}
		});
		buttonPanel.add(btnNewCattle);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(bovinePanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		panel.repaint();
	}
	
	/**
	 * Show the details for this Bovine with the given ID
	 * @param bovineID The internal Id that identifies this Bovine
	 * @param bovines The Bull and/or Cow to set as Dame and Sire for this Bovine
	 * @return <tt>true</tt> If a Bovine with the Id exists and was shown, <tt>false</tt> otherwise.
	 */
	public boolean createBovinePanel(long bovineID, Bovine... bovines){
		boolean value = createBovinePanel(bovineID);
		
		for(Bovine b :bovines){
			if(b.getGender().equals(Bull.GENDER)){
				BovineList<Bull> blb = new BovineList<Bull>((Bull)b);
				if(!bullList.contains(blb)){
					bullList.add(blb);
					lstSire.setModel(new DefaultComboBoxModel(bullList.toArray()));
				}
				lstSire.setSelectedIndex(bullList.indexOf(blb));
			}else if(b.getGender().equals(Cow.GENDER)){
				BovineList<Cow> blc = new BovineList<Cow>((Cow)b);
				if(!cowList.contains(blc)){
					cowList.add(blc);
					lstDame.setModel(new DefaultComboBoxModel(cowList.toArray()));
				}
				lstDame.setSelectedIndex(cowList.indexOf(blc));
			}
		}
		
		return value;
	}

	/**
	 * Show the details for this Bovine with the given ID
	 * @param bovineID The internal Id that identifies this Bovine
	 * @return <tt>true</tt> If a Bovine with the Id exists and was shown, <tt>false</tt> otherwise.
	 */
	public boolean createBovinePanel(final long bovineID){
		if(bList==null){
			// Use case for initial load without showing list.
			bList=LivestockSolutions.getBovines();
			viewing=VIEW;
		}
		if(viewing==CATTLE_LIST){
			viewing=VIEW;
		}
		if(bovineViewID != bovineID){
			bullList.clear();
			cowList.clear();
			bovineViewID = bovineID;
			if(jisp.getParent()!=null)
				jisp.getParent().remove(jisp);
			jisp = new JTabbedPane();
			
			if(bovineID!=-1){
				edit=false;
			}else{
				edit=true;
			}
			txtVisualID.setText("-1");
			lstMob.setSelectedItem(null);
			lstGender.setSelectedIndex(0);
		}
		
		panel.setLayout(new BorderLayout(10, 10));
		remove(search);
		panel.removeAll();
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10, 10));
		JPanel flowPanel = new JPanel();
		JPanel panelID = new JPanel();
		panelID.setLayout(new BorderLayout(0, 10));
		flowPanel.add(panelID);
		container.add(flowPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		
		list.clearMenu();
		/**
		 * The Bovine that is being shown.
		 */
		JButton btnHome = new JButton("Cattle List");
		btnHome.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=false;
				txtVisualID.setText("-1");
				viewing=-1;
				list.clearMenu();
				remove(list);
				bovineOffspringAddList.clear();
				bovineGroupAddList.clear();
				
				jisp = new JTabbedPane();
				observationsListPanel = new JPanel();
				offspringListPanel = new JPanel();
				weighingsListPanel = new JPanel();
				groupsListPanel = new JPanel();
				medicinesListPanel = new JPanel();
				vetVisitsListPanel = new JPanel();
				feedsListPanel = new JPanel();
				joiningListPanel = new JPanel();
				displayPanel(CATTLE_LIST);
			}
		});
		list.add(SidePanel.TOP,btnHome);
		
		// Create a new list of cattle with only Visual ID - in same order and list as the full list.
		final Table bovinePanel = new Table("Cattle List",false,"Visual ID");
		bovinePanel.setHeaderClickable(0, false);
		bovinePanel.setEmptyMessage("0 Cattle.");
		for(int x=0; x<bList.length; x++){
			bovinePanel.addRow(new JLabel(bList[x].getEartag().getEartagID()));
			if(b!=null&&b.getID()==bList[x].getID()){
				bovinePanel.setSelected(true);
			}
			final long id = bList[x].getID();
			bovinePanel.addMouseListener(new MouseListener(){
				@Override
				public void mouseClicked(MouseEvent e) {
					createBovinePanel(id);
				}
				@Override public void mousePressed(MouseEvent e) {}
				@Override public void mouseReleased(MouseEvent e) {}
				@Override public void mouseEntered(MouseEvent e) {}
				@Override public void mouseExited(MouseEvent e) {}
			});
		}

		list.add(SidePanel.CENTRE,bovinePanel);
		add(list,BorderLayout.WEST);
		// Finish Cattle list

		// Set up Edit, Cancel, Save Buttons on top of Cattle view area.
		if(bovineID==-1 || b!=null){
			JButton btnCancel = new JButton(bovineID!=-1?"Cancel":"Clear");
			btnCancel.setVisible(edit);
			btnCancel.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					if(bovineID!=-1){
						edit=false;
					}
					txtVisualID.setText("-1");
					
					bovineOffspringAddList.clear();
					bovineGroupAddList.clear();
					
					lstMob.setSelectedItem(null);
					displayPanel(viewing);
				}
			});
			
			JButton btnCreateSave = new JButton(bovineID==-1?"Create":edit?"Save":"Edit");
			btnCreateSave.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					if(edit){
						Bovine b = LivestockSolutions.getBovineByID(bovineID);
						String visual = txtVisualID.getText().trim();
						String nlisID = txtNlisID.getText().trim().toUpperCase();
						String rfID = txtRFID.getText().trim().toUpperCase();
						
						//Check that no active Cattle exist with any of the same Visual IDs
						for(Bovine bo : LivestockSolutions.getActiveBovines()){
							if(bo!=b){
								if(!visual.equals("")&&visual.equals(bo.getEartag().getEartagID())){
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"Another active animal currently has the same Visual Eartag: "+visual+".\nPlease alter this animals Visual Eartag and try again." ,"Visual ID is already in use", JOptionPane.OK_OPTION);
									return;
								}
								
								if(!nlisID.equals("")&&nlisID.equals(bo.getEartag().getNlisID())){
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"Another active animal currently has the same NLIS ID: "+nlisID+".\nPlease alter this animals NLIS ID and try again." ,"NLIS ID is already in use", JOptionPane.OK_OPTION);
									return;
								}
								
								if(!rfID.equals("")&&rfID.equals(bo.getEartag().getRfID())){
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"Another active animal currently has the same RF ID: "+rfID+".\nPlease alter this animals RF ID and try again." ,"RF ID is already in use", JOptionPane.OK_OPTION);
									return;
								}
							}
						}
						
						Date dob = txtDOB.getDate();
						Date activeD = null;
						Date inactiveD = null;
						if(b==null || b.getDob()==null || b.getGender().equals(Bovine.GENDER)){
							if(!txtDOB.isEmpty()&&dob!=null){
								if(b!=null){
									for(Bovine of : b.getOffspring()){
										
										if(of.getDob()!=null){
											int days = (of.getGender().equals(Bull.GENDER)?of.getBreed().getAverageMalePubityAgeInDays():of.getBreed().getAverageFemalePubityAgeInDays())+of.getBreed().getGestationPeriodInDays()-30;
											Calendar cal = Calendar.getInstance();
											cal.setTime(of.getDob());
											cal.add(Calendar.DATE, -days);
											if(!dob.before(cal.getTime())){
												JOptionPane.showMessageDialog(MainFrame.getInstance(),"The date for DOB ("+txtDOB.getText()+")  is set to a date after an Offspring was conceived: "+JDatePickerDate.format(cal.getTime())+".","Invalid DOB", JOptionPane.OK_OPTION);
												return;
											}
										}
									}
									
									if(b.getDame()!=null&&b.getDame().getDob()!=null){
										int days = b.getDame().getBreed().getAverageFemalePubityAgeInDays()+b.getDame().getBreed().getGestationPeriodInDays()-30;
										Calendar cal = Calendar.getInstance();
										cal.setTime(b.getDame().getDob());
										cal.add(Calendar.DATE, -days);
										if(dob.before(cal.getTime())){
											JOptionPane.showMessageDialog(MainFrame.getInstance(),"The date for DOB ("+txtDOB.getText()+")  is set to a date before this animals Dame would be considered mature: "+JDatePickerDate.format(cal.getTime())+".","Invalid DOB", JOptionPane.OK_OPTION);
											return;
										}
									}
									
									if(b.getSire()!=null&&b.getSire().getDob()!=null){
										int days = b.getSire().getBreed().getAverageMalePubityAgeInDays()+b.getSire().getBreed().getGestationPeriodInDays()-30;
										Calendar cal = Calendar.getInstance();
										cal.setTime(b.getSire().getDob());
										cal.add(Calendar.DATE, -days);
										if(dob.before(cal.getTime())){
											JOptionPane.showMessageDialog(MainFrame.getInstance(),"The date for DOB ("+txtDOB.getText()+")  is set to a date before this animals Sire would be considered mature: "+JDatePickerDate.format(b.getSire().getDob())+".","Invalid DOB", JOptionPane.OK_OPTION);
											return;
										}
									}
								}
								
								if(dob.after(new Date())){
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"The date for DOB ("+txtDOB.getText()+")  is set to a date in the future.","Invalid DOB", JOptionPane.OK_OPTION);
									return;
								}
							}else if(!txtDOB.isEmpty()) {
								JOptionPane.showMessageDialog(MainFrame.getInstance(),"The date for DOB ("+txtDOB.getText()+")  is not valid.","Invalid DOB", JOptionPane.OK_OPTION);
							}
							if(bovineID==-1){
								activeD = txtAcquireDate.getDate();
								if(activeD==null){
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"The acquire date can not be empty.","Invalid Date", JOptionPane.OK_OPTION);
									return;
								}
							}
						}
						
						if(b!=null&&!btnSetInactive.isEnabled()){
							inactiveD = txtDeacquireDate.getDate();
							if(b.getAcquisition()!=null&&b.getAcquisition().getDate()!=null&&b.getAcquisition().getDate().after(inactiveD)){
								JOptionPane.showMessageDialog(MainFrame.getInstance(),"The date given ("+txtDeacquireDate.getText()+")  is set before this animal was acquired.","Invalid Date", JOptionPane.OK_OPTION);
								return;
							}
						}
						
						if(b!=null&&!btnSetInactive.isEnabled()&&inactiveD==null){
							JOptionPane.showMessageDialog(MainFrame.getInstance(),"Could not update inactive date ("+txtDeacquireDate.getText()+").\nDate is not valid or is empty","Invalid Date", JOptionPane.OK_OPTION);
							return;
						}
							
						if((nlisID.length()==nlisIDLength||nlisID.equals(""))&&(rfID.length()==rfIDLength||rfID.equals(""))){
							if(bovineID==-1){
								b = new Bovine(null);
								// Set these on creation of an new Animal
								String method = (String)lstAcquireMethod.getSelectedItem();
								Owner po = null;
								float price = 0f;
								if(!method.trim().toLowerCase().equals("birth")){
									po = new Owner();
									po.setName((String)lstPreviousOwner.getSelectedItem());
									for(Owner o : LivestockSolutions.getOwners()){
										po = o.getName().toLowerCase().equals(((String)lstPreviousOwner.getSelectedItem()).trim().toLowerCase())?o:po;
									}
									LivestockSolutions.addOwner(po);
									price = Float.parseFloat(txtAcquirePrice.getText());
								}else{
									if(dob!=null){
										activeD=dob;
									}
								}
								b.setAcquisition(new Acquisition(method,price,po,activeD));
								
								CattleBreed br = LivestockSolutions.getCattleBreed((String)lstBreed.getSelectedItem());
								if(br==null){
									// Create new Breed with default values.
									LivestockSolutions.addCattleBreed((String)lstBreed.getSelectedItem(), 0f, 0f, 0f, 0f, 0f, 0, 0, 0);
									br = LivestockSolutions.getCattleBreed((String)lstBreed.getSelectedItem());
								}
								
								b.setBreed(br);
								b.setEartag(new Eartag());
							}
							
							if(b==null){
								JOptionPane.showMessageDialog(MainFrame.getInstance(),"Cattle could not be created or updated.","Problem updating or creating Cattle", JOptionPane.ERROR_MESSAGE);
								return;
							}
							
							// Always set these
							b.getEartag().setEartagID(visual);
							b.getEartag().setNlisID(nlisID);
							b.getEartag().setRfID(rfID);
							
							if(b.getDob()==null || b.getGender().equals(Bovine.GENDER)){
								if(dob!=null){
									b.setDOB(dob);
								}
								Class<? extends Bovine> gC = lstGender.getSelectedItem().equals(Cow.GENDER)?Cow.class:lstGender.getSelectedItem().equals(Bull.GENDER)?Bull.class:null;
								if(gC!=null){
									String gender = b.getGender();
									b=b.setGender(gC);
									if(gender.equals(Bovine.GENDER)&&gender.equals(b.getGender())){
										JOptionPane.showMessageDialog(MainFrame.getInstance(),"Could not change the gender from "+b.getGender()+", to "+(lstGender.getSelectedItem().equals(Cow.GENDER)?Cow.GENDER:lstGender.getSelectedItem().equals(Bull.GENDER)?Bull.GENDER:Bovine.GENDER),"Gender Change Failed", JOptionPane.OK_OPTION);
									}
								}
							}
							// Set these after animal has been created, only if it is being set
							if(btnSetInactive==null){
								btnSetInactive=new JButton("Set Inactive");
							}
							if(!btnSetInactive.isEnabled()){
								Owner po = null;
								float price = 0f;
								String method = (String)lstDeacquireMethod.getSelectedItem();
								if(!method.trim().toLowerCase().equals("death")){
									po = new Owner();
									po.setName((String)lstNewOwner.getSelectedItem());
									for(Owner o : LivestockSolutions.getOwners()){
										po = o.getName().toLowerCase().equals(((String)lstNewOwner.getSelectedItem()).trim().toLowerCase())?o:po;
									}
									price = Float.parseFloat(sellPrice.getText());
									LivestockSolutions.addOwner(po);
								}
								b.setDeacquisition(new Deacquisition(method,price,po,inactiveD));
							}
							
							// Set values that may have an effect on other Objects. Beyond this point this Bovine is valid.
							b.setMob(lstMob.getSelectedIndex()>0?mobList[lstMob.getSelectedIndex()-1]:null);
							
							// Set these if not already set
							if(b.getDame()==null&&lstDame.getSelectedIndex()>0){
								b.setDame(cowList.get(lstDame.getSelectedIndex()).getItem());
							}
							
							if(b.getSire()==null&&lstSire.getSelectedIndex()>0){
								b.setSire(bullList.get(lstSire.getSelectedIndex()).getItem());
							}
							// update 
							if(LivestockSolutions.addBovine(b)){
								BovinePanel.this.bovineViewID=b.getID();
								btnSetInactive=null;
								
								String error = "";
								for(Bovine bo : bovineOffspringAddList){
									if(b.getGender().equals(Cow.GENDER)){
										if(!bo.setDame((Cow)b)) {
											error+=", "+bo.getEartag().getEartagID();
										}
									}else if(b.getGender().equals(Bull.GENDER)){
										if(!bo.setSire((Bull)b)) {
											error+=", "+bo.getEartag().getEartagID();
										}
									}
								}
								
								if(error.equals("")) {
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"Cattle "+(bovineID==-1?"creation":"update")+" was successfull.",(bovineID==-1?"New Cattle was created":"Cattle was updated")+" successfully", JOptionPane.INFORMATION_MESSAGE);
								}else {
									JOptionPane.showMessageDialog(MainFrame.getInstance(),"Cattle "+(bovineID==-1?"creation":"update")+" was successfull.",(bovineID==-1?"New Cattle was created":"Cattle was updated")+" successfully", JOptionPane.INFORMATION_MESSAGE);
									
								}
								ArrayList<Group> groupList = new ArrayList<Group>(Arrays.asList(b.getGroups()));
								groupList.add(b.getBelongingMob());
								for(Group g : bovineGroupAddList){
									if(groupList.contains(g)){
										if(g instanceof Mob){
											b.setMob(null);
										}else{
											b.removeGroup(g);
										}
									}else{
										if(g instanceof Mob){
											b.setMob((Mob)g);
										}else{
											b.addGroup(g);
										}
									}
								}
								
								bovineGroupAddList.clear();
								bovineOffspringAddList.clear();
								txtVisualID.setText("-1");
								edit=!edit;
							}else{
								JOptionPane.showMessageDialog(MainFrame.getInstance(),"Failed to save changes.","Failed to Save", JOptionPane.OK_OPTION);
							}
						}else{
							String start = "";
							String title = "Invalid";
							if(nlisID.length()!=nlisIDLength&&!nlisID.equals("")){
								start +="Nlis id must be "+nlisIDLength+" characters in length, or empty\n";
								title +="Nlis";
							}
							if(rfID.length()!=nlisIDLength&&!rfID.equals("")){
								start +="RF id must be "+rfIDLength+" characters in length, or empty\n";
								title +=(title.equals("Invalid")?"":" and ")+"RF";
							}
							
							JOptionPane.showMessageDialog(MainFrame.getInstance(),start,title, JOptionPane.OK_OPTION);
						}
					}else{
						txtVisualID.setText("-1");
						edit=!edit;
					}
					displayPanel(viewing);
				}
			});

			btnCreateSave.setEnabled(true);
			btnCancel.setEnabled(btnCreateSave.isEnabled());
			
			JPanel buttonMenu = new JPanel();
			((FlowLayout)buttonMenu.getLayout()).setAlignment(FlowLayout.RIGHT);
			buttonMenu.add(btnCreateSave);
			buttonMenu.add(btnCancel);
			container.add(buttonMenu,BorderLayout.NORTH);
		}
		
		CattleBreed[] cattleBreed = LivestockSolutions.getBreeds();
		String[] strBreedList = new String[cattleBreed.length];
		int selected = 0;
		for(int x=0; x<cattleBreed.length; x++){
			strBreedList[x]=cattleBreed[x].getBreedName();
			if(b!=null && b.getBreed()==cattleBreed[x]){
				selected=x;
			}
		}
		
		if(b!=null || bovineID==-1){
			String visualID="";
			String nlisID="";
			String rfID="";
			Date dob = new Date();
			final Mob bellongingMob = b!=null?b.getBelongingMob():null;

			boolean refresh=false;
			if(!txtVisualID.getText().equals("-1")){
				refresh=true;
			}
			if(b!=null){
				visualID=b.getEartag().getEartagID();
				nlisID=b.getEartag().getNlisID();
				rfID=b.getEartag().getRfID();
				dob=b.getDob();
				if(refresh){
					if(b.getGender().toLowerCase().equals("male")){
						lstGender.setSelectedIndex(1);
					}else if(b.getGender().toLowerCase().equals("female")){
						lstGender.setSelectedIndex(2);
					}else{
						lstGender.setSelectedIndex(0);
					}
				}
			}else{
				if(bovineID==-1){
					edit=true;
				}
			}
			
			Object selectedObject = lstBreed.getSelectedItem();
			
			lstBreed.setModel(new DefaultComboBoxModel(strBreedList));
			lstBreed.setEnabled(edit);
			if(strBreedList.length>0){
				if(selectedObject==null){
					lstBreed.setSelectedIndex(selected);
				}else{
					lstBreed.setSelectedItem(selectedObject);
				}
			}
			
			selectedObject = lstMob.getSelectedItem();
			mobList = LivestockSolutions.getOnlyMobs();
			String[] strMobList = new String[mobList.length+1];
			strMobList[0]="No Mob";
			selected = 0;
			for(int x=0; x<mobList.length; x++){
				strMobList[x+1]=mobList[x].getName();
				if(b!=null && b.getBelongingMob()==mobList[x]){
					selected=x+1;
				}
			}
			
			lstMob.setModel(new DefaultComboBoxModel(strMobList));
			lstMob.setEnabled(edit);
			if(selectedObject==null){
				lstMob.setSelectedIndex(selected);
			}else{
				lstMob.setSelectedItem(selectedObject);
			}
		
			Owner[] owners = LivestockSolutions.getOwners();
			String[] strOwnerList = new String[owners.length];
			for(int x=0; x<owners.length; x++){
				strOwnerList[x]=owners[x].getName();
			}
			
			Object selectedPrevObject = lstPreviousOwner.getSelectedItem();
			Object selectedNextObject = lstNewOwner.getSelectedItem();
			
			selectedObject = lstPreviousOwner.getSelectedItem();
			lstPreviousOwner.setModel(new DefaultComboBoxModel(strOwnerList));
			if(selectedNextObject!=null){
				lstPreviousOwner.setSelectedItem(selectedObject);
			}

			selectedObject = lstNewOwner.getSelectedItem();
			lstNewOwner.setModel(new DefaultComboBoxModel(strOwnerList));
			if(selectedPrevObject!=null){
				lstNewOwner.setSelectedItem(selectedObject);
			}
			
			// Get a list of possible Dame and Sires.
			Bovine[] bovines = LivestockSolutions.getBovines();
			
			int sireSelected = 0;
			int dameSelected = 0;

			BovineList<Bull> blbn = new BovineList<Bull>(null);
			BovineList<Cow> blcn = new BovineList<Cow>(null);
			if(!bullList.contains(blbn)){
				bullList.add(blbn);
			}
			if(!cowList.contains(blcn)){
				cowList.add(blcn);
			}
			
			for(Bovine bovine : bovines){
				int days = bovine.getBreed().getGestationPeriodInDays()-30;
//				int days = bovine.getBreed().getAveragePubityAgeInDays()+bovine.getBreed().getGestationPeriodInDays()-30;
				Calendar cal = Calendar.getInstance();
				cal.add(Calendar.DATE, -days);
				if(bovine.getDob() == null || bovine.getDob().before(cal.getTime())){
					if(bovine.getGender().equals(Bull.GENDER)){	
						// The Bull could be a Father.
						if(b!=null&&b.getSire()!=null&&b.getSire()==bovine){
							sireSelected=bullList.size();
						}
						BovineList<Bull> blb = new BovineList<Bull>((Bull)bovine);
						if(!bullList.contains(blb)){
							bullList.add(blb);
						}
					}else if(bovine.getGender().equals(Cow.GENDER)){
						// The Cow could be the mother
						if(b!=null&&b.getDame()!=null&&b.getDame()==bovine){
							dameSelected=cowList.size();
						}
						BovineList<Cow> blc = new BovineList<Cow>((Cow)bovine);
						if(!cowList.contains(blc)){
							cowList.add(blc);
						}
					}
				}
			}

			if(!refresh){
				jisp = new JTabbedPane();
				observationsListPanel = new JPanel();
				offspringListPanel = new JPanel();
				weighingsListPanel = new JPanel();
				groupsListPanel = new JPanel();
				medicinesListPanel = new JPanel();
				vetVisitsListPanel = new JPanel();
				feedsListPanel = new JPanel();
				joiningListPanel = new JPanel();
				
				jisp.setOpaque(false);
				jisp.setBorder(new EmptyBorder(0,0,0,0));
				jisp.addTab("Observations",MainFrame.scale(MainFrame.getImageIcon(MainFrame.OBSERVATION_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), observationsListPanel);
				jisp.addTab("Offspring",MainFrame.scale(MainFrame.getImageIcon(MainFrame.CATTLE_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), offspringListPanel);
				jisp.addTab("Joinings",MainFrame.scale(MainFrame.getImageIcon(MainFrame.JOINING_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), joiningListPanel);
				jisp.addTab("Weighings",MainFrame.scale(MainFrame.getImageIcon(MainFrame.WEIGHT_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), weighingsListPanel);
				jisp.addTab("Groups",MainFrame.scale(MainFrame.getImageIcon(MainFrame.GROUP_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), groupsListPanel);
				jisp.addTab("Given Medicines",MainFrame.scale(MainFrame.getImageIcon(MainFrame.MEDICINE_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), medicinesListPanel);
				jisp.addTab("Vet Visits",MainFrame.scale(MainFrame.getImageIcon(MainFrame.CATTLE_VET_VISIT_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), vetVisitsListPanel);
				jisp.addTab("Given Feeds",MainFrame.scale(MainFrame.getImageIcon(MainFrame.FEED_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), feedsListPanel);
				jisp.addMouseListener(new MouseListener(){
					@Override public void mouseClicked(MouseEvent e) {}
					@Override public void mousePressed(MouseEvent e) {
						new Thread(){@Override
						public void run(){
							if(jisp.getSelectedComponent()==observationsListPanel)
								createObservationsPanel(bovineID);
							else if(jisp.getSelectedComponent()==offspringListPanel)
								createOffspringPanel(bovineID);
							else if(jisp.getSelectedComponent()==joiningListPanel)
								createJoiningsPanel(bovineID);
							else if(jisp.getSelectedComponent()==weighingsListPanel)
								createWeightsPanel(bovineID);
							else if(jisp.getSelectedComponent()==groupsListPanel)
								createGroupsPanel(bovineID);
							else if(jisp.getSelectedComponent()==medicinesListPanel)
								createMedicinePanel(bovineID);
							else if(jisp.getSelectedComponent()==vetVisitsListPanel)
								createMedicalPanel(bovineID);
							else if(jisp.getSelectedComponent()==feedsListPanel)
								createFeedPanel(bovineID);
						}}.start();
					}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				jisp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
				jisp.setAutoscrolls(true);
				
				jisp.setBorder(new EmptyBorder(0,0,0,0));
			}
			panel.add(jisp,BorderLayout.CENTER);
			
			JPanel idPanel = new JPanel();
			panelID.add(idPanel, BorderLayout.NORTH);
			idPanel.setLayout(new BoxLayout(idPanel, BoxLayout.X_AXIS));
			
			JPanel idNamePanel = new JPanel();
			idPanel.add(idNamePanel);
			idNamePanel.setLayout(new BoxLayout(idNamePanel, BoxLayout.PAGE_AXIS));
			
			JPanel visualIDNamePanel = new JPanel();
			FlowLayout flowLayout_3 = (FlowLayout) visualIDNamePanel.getLayout();
			flowLayout_3.setHgap(0);
			flowLayout_3.setAlignment(FlowLayout.LEADING);
			idNamePanel.add(visualIDNamePanel);
			
			JLabel lblvisualID = new JLabel("Visual ID:");
			visualIDNamePanel.add(lblvisualID);
			
			JPanel nlisIDNamePanel = new JPanel();
			FlowLayout flowLayout_4 = (FlowLayout) nlisIDNamePanel.getLayout();
			flowLayout_4.setHgap(0);
			flowLayout_4.setAlignment(FlowLayout.LEADING);
			idNamePanel.add(nlisIDNamePanel);
			
			JLabel lblNlisID = new JLabel("NLIS ID:");
			nlisIDNamePanel.add(lblNlisID);
			
			JPanel rfIDNamePanel = new JPanel();
			FlowLayout flowLayout_5 = (FlowLayout) rfIDNamePanel.getLayout();
			flowLayout_5.setHgap(0);
			flowLayout_5.setAlignment(FlowLayout.LEADING);
			idNamePanel.add(rfIDNamePanel);
			
			JLabel lblRFID = new JLabel("RF ID:");
			rfIDNamePanel.add(lblRFID);
			
			JPanel mobNamePanel = new JPanel();
			FlowLayout flowLayout = (FlowLayout) mobNamePanel.getLayout();
			flowLayout.setHgap(0);
			flowLayout.setAlignment(FlowLayout.LEADING);
			flowLayout.setVgap(8);
			idNamePanel.add(mobNamePanel);
			
			JLabel lblMob = new JLabel("Mob:");
			mobNamePanel.add(lblMob);
			
			JPanel breedNamePanel = new JPanel();
			FlowLayout flowLayout_1 = (FlowLayout) breedNamePanel.getLayout();
			flowLayout_1.setHgap(0);
			flowLayout_1.setAlignment(FlowLayout.LEADING);
			flowLayout_1.setVgap(8);
			idNamePanel.add(breedNamePanel);
			
			JLabel lblBreed = new JLabel("Breed:");
			breedNamePanel.add(lblBreed);
			
			JPanel idValuePanel = new JPanel();
			idPanel.add(idValuePanel);
			idValuePanel.setLayout(new BoxLayout(idValuePanel, BoxLayout.PAGE_AXIS));
			
			JPanel idVisualValuePanel = new JPanel();
			idValuePanel.add(idVisualValuePanel);
			idVisualValuePanel.setLayout(new BorderLayout(0, 0));
			
			txtVisualID.setText(refresh?txtVisualID.getText():visualID);
			txtVisualID.setEditable(edit);
			idVisualValuePanel.add(txtVisualID);
			
			JPanel idNlisValuePanel = new JPanel();
			idValuePanel.add(idNlisValuePanel);
			idNlisValuePanel.setLayout(new BorderLayout(0, 0));
			
			txtNlisID.setText(refresh?txtNlisID.getText():nlisID);
			txtNlisID.setEditable(edit);
			idNlisValuePanel.add(txtNlisID, BorderLayout.CENTER);
			
			JPanel idRfValuePanel = new JPanel();
			idValuePanel.add(idRfValuePanel);
			idRfValuePanel.setLayout(new BorderLayout(0, 0));
			
			txtRFID.setText(refresh?txtRFID.getText():rfID);
			txtRFID.setEditable(edit);
			idRfValuePanel.add(txtRFID);
			
			JPanel mobValuePanel = new JPanel();
			idValuePanel.add(mobValuePanel);
			mobValuePanel.setLayout(new BorderLayout(5, 0));
			
			mobValuePanel.add(lstMob, BorderLayout.CENTER);
			
			JButton btnMobView = new JButton("Show Mob");
			mobValuePanel.add(btnMobView, BorderLayout.EAST);
			
			JPanel breedValuePanel = new JPanel();
			idValuePanel.add(breedValuePanel);
			breedValuePanel.setLayout(new BorderLayout(0,0));
			
			if(!edit && b!=null){
				JButton btnBreed = new JButton(b.getBreed().getBreedName());
				breedValuePanel.add(btnBreed,BorderLayout.CENTER);
				btnBreed.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						breedDetails(b.getBreed().getBreedName());
					}
				});
			}else{
				JPanel breedValueBreedSelectListPanel = new JPanel();
				breedValuePanel.add(breedValueBreedSelectListPanel,BorderLayout.CENTER);
				breedValueBreedSelectListPanel.setLayout(new BorderLayout(5, 0));
			
				breedValueBreedSelectListPanel.add(lstBreed, BorderLayout.CENTER);
				lstBreed.setEditable(edit);
			}
			
			btnMobView.setEnabled(bellongingMob!=null);
			if(bellongingMob!=null){
				btnMobView.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						MainFrame.getInstance().showMob(bellongingMob.getID());
					}
				});
			}
			
			JPanel panelBreed = new JPanel();
			panelID.add(panelBreed, BorderLayout.CENTER);
			panelBreed.setLayout(new BorderLayout(0, 10));
			
			JPanel slaughterPanel = new JPanel();
			if(b!=null&&b.getSafeSlaughterDate()!=null&&!b.getSafeSlaughterDate().before(new Date())){
				panelBreed.add(slaughterPanel, BorderLayout.NORTH);
			}
			
			JLabel lblSafeSlaughter = new JLabel("Withhold before:");
			slaughterPanel.add(lblSafeSlaughter);
			
			JLabel lblSafeSlaughterDate = new JLabel(b!=null&&b.getSafeSlaughterDate()!=null?JDatePickerDate.format(b.getSafeSlaughterDate()):"");
			slaughterPanel.add(lblSafeSlaughterDate);
			
			JPanel dobGenderPanel = new JPanel();
			panelBreed.add(dobGenderPanel, BorderLayout.CENTER);
			dobGenderPanel.setLayout(new BoxLayout(dobGenderPanel, BoxLayout.X_AXIS));
			
			JPanel genderPanel = new JPanel();
			dobGenderPanel.add(genderPanel);
			genderPanel.setLayout(new BorderLayout(0,0));
			
			if(bovineID==-1||(b!=null&&b.getGender().toLowerCase().equals(Bovine.GENDER.toLowerCase()))&&edit){
				JPanel genderValuePanel = new JPanel();
				genderPanel.add(genderValuePanel,BorderLayout.CENTER);
				genderValuePanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblGenderName = new JLabel("Gender:");
				genderValuePanel.add(lblGenderName, BorderLayout.WEST);
				
				JPanel genderValueListPanel = new JPanel();
				genderValuePanel.add(genderValueListPanel);
				genderValueListPanel.setLayout(new BorderLayout(0, 0));
				
				genderValueListPanel.add(lstGender, BorderLayout.NORTH);
			}else{
				JLabel lblGender = new JLabel("Gender: "+(b!=null?b.getGender():Bovine.GENDER));
				genderPanel.add(lblGender,BorderLayout.CENTER);
			}

			JPanel dobPanel = new JPanel();
			dobPanel.setBorder(new EmptyBorder(0,10,0,5));
			dobGenderPanel.add(dobPanel);
			dobPanel.setLayout(new BorderLayout(5, 0));
			
			JLabel lblDOB = new JLabel("DOB:");
			dobPanel.add(lblDOB, BorderLayout.WEST);

			txtDOB.setDate(refresh?txtDOB.getDate():dob);
			txtDOB.setEnabled((b==null||b.getDob()==null||b.getGender().equals(Bovine.GENDER))&&edit);
			
			dobPanel.add(txtDOB, BorderLayout.CENTER);
			
			JPanel panelAcquisition = new JPanel();
			panelBreed.add(panelAcquisition, BorderLayout.SOUTH);
			panelAcquisition.setLayout(new BorderLayout(0, 10));
			
			JPanel acquisitionPanel = new JPanel();
			panelAcquisition.add(acquisitionPanel, BorderLayout.NORTH);
			acquisitionPanel.setLayout(new BorderLayout(5, 0));
			
			JPanel acquireDatePanel = new JPanel();
			acquisitionPanel.add(acquireDatePanel, BorderLayout.WEST);
			acquireDatePanel.setLayout(new BorderLayout(5, 0));

			acquireDatePanel.add(new JLabel("Acquired On:"), BorderLayout.WEST);
			
			JPanel acquireValuePanel = new JPanel();
			acquireDatePanel.add(acquireValuePanel);
			acquireValuePanel.setLayout(new BorderLayout(0, 0));			
			
			txtAcquireDate.setDate(refresh?txtAcquireDate.getDate():b!=null&&b.getAcquisition()!=null&&b.getAcquisition().getDate()!=null?b.getAcquisition().getDate():new Date());
			txtAcquireDate.setEnabled(edit&& (b==null ||b.getAcquisition()==null));
			acquireValuePanel.add(txtAcquireDate);
			
			JPanel acquireMethodPanel = new JPanel();
			acquisitionPanel.add(acquireMethodPanel, BorderLayout.CENTER);
			acquireMethodPanel.setLayout(new BorderLayout(5, 0));
			
			JLabel lblAcquireBy = new JLabel("By:");
			acquireMethodPanel.add(lblAcquireBy, BorderLayout.WEST);
			
			JPanel acquireMethodValuePanel = new JPanel();
			acquireMethodPanel.add(acquireMethodValuePanel);
			acquireMethodValuePanel.setLayout(new BorderLayout(0, 0));

			final JPanel acquirePurchasePanel = new JPanel();
			acquisitionPanel.add(acquirePurchasePanel, BorderLayout.SOUTH);
			acquirePurchasePanel.setLayout(new BoxLayout(acquirePurchasePanel,BoxLayout.X_AXIS));
			
			txtDOB.addPropertyChangeListener("value",new PropertyChangeListener(){
				@Override
				public void propertyChange(PropertyChangeEvent arg0) {
					Object value = lstAcquireMethod.getSelectedItem();
					txtAcquireDate.setDate(value.equals("Purchase")?txtAcquireDate.getDate():txtDOB.getDate()!=null?txtDOB.getDate():txtAcquireDate.getDate());
				}
			});

			if(bovineID==-1){
				acquireMethodValuePanel.add(lstAcquireMethod, BorderLayout.CENTER);
				txtAcquireDate.setEnabled(lstAcquireMethod.getSelectedItem().equals("Purchase"));
				lstAcquireMethod.addActionListener(new ActionListener(){
					@Override
					public void actionPerformed(ActionEvent e) {
						Object value = lstAcquireMethod.getSelectedItem();
						acquirePurchasePanel.setVisible(value.equals("Purchase"));
						txtAcquireDate.setEnabled(value.equals("Purchase"));
						txtAcquireDate.setDate(value.equals("Purchase")?txtAcquireDate.getDate():txtDOB.getDate()!=null?txtDOB.getDate():txtAcquireDate.getDate());
					}
				});
			}else{
				JLabel lblAcquireMethod = new JLabel(b!=null&&b.getAcquisition()!=null&&b.getAcquisition().getMethod()!=null?b.getAcquisition().getMethod():"Unknown");
				acquireMethodValuePanel.add(lblAcquireMethod, BorderLayout.CENTER);
			}

			JPanel acquirePurchasePricePanel = new JPanel();
			acquirePurchasePanel.add(acquirePurchasePricePanel);
			acquirePurchasePricePanel.setBorder(new EmptyBorder(0,0,0,10));
			acquirePurchasePricePanel.setLayout(new BorderLayout(5, 0));
			
			acquirePurchasePricePanel.add(new JLabel("Cost: $"),BorderLayout.WEST);
			txtAcquirePrice.setColumns(10);
			txtAcquirePrice.setText(refresh?txtAcquirePrice.getText():b!=null&&b.getAcquisition()!=null?String.valueOf(b.getAcquisition().getPrice()):"0.00");
			txtAcquirePrice.setEnabled(edit&& (b==null ||b.getAcquisition()==null));
			acquirePurchasePricePanel.add(txtAcquirePrice,BorderLayout.CENTER);
			
			JPanel acquirePurchaseOwnerPanel = new JPanel();
			acquirePurchasePanel.add(acquirePurchaseOwnerPanel);
			acquirePurchaseOwnerPanel.setLayout(new BorderLayout(5, 0));
			
			JLabel lblOwner = new JLabel("Previous Owner:");
			lblOwner.setHorizontalAlignment(SwingConstants.RIGHT);
			acquirePurchaseOwnerPanel.add(lblOwner, BorderLayout.WEST);
	
			if(bovineID==-1){
				JPanel ownerFromSelectNewPanel = new JPanel();
				acquirePurchaseOwnerPanel.add(ownerFromSelectNewPanel);
				ownerFromSelectNewPanel.setLayout(new BoxLayout(ownerFromSelectNewPanel, BoxLayout.X_AXIS));
				ownerFromSelectNewPanel.add(lstPreviousOwner);
				lstPreviousOwner.setEditable(true);
			}else{
				if(b!=null){
					final JButton btnOwner = new JButton(b.getAcquisition()!=null&&b.getAcquisition().getOwner()!=null?b.getAcquisition().getOwner().getName():"N/A");
					btnOwner.setEnabled(b.getAcquisition()!=null&&b.getAcquisition().getOwner()!=null);
					acquirePurchaseOwnerPanel.add(btnOwner,BorderLayout.CENTER);
					
					btnOwner.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							if(!MainFrame.getInstance().showOwner(b.getAcquisition().getOwner().getID())){
								// Show Owner not found message?
								btnOwner.setEnabled(false);
							}
						}
					});
				}
			}
			
			if(!refresh || btnSetInactive==null){	
				btnSetInactive = new JButton("Set Inactive");
				sellPrice.setText("0.00");
			}
			if(b!=null){
				JPanel activePanel = new JPanel();
				final JPanel inactivePanel = new JPanel();
				
				panelAcquisition.add(activePanel, BorderLayout.CENTER);
				
				btnSetInactive.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						edit=true;
						inactivePanel.setVisible(true);
						btnSetInactive.setEnabled(false);
						txtDeacquireDate.setEnabled(edit&&(b.getDeacquisition()==null));
						txtDeacquireDate.setDate(new Date());
					}
				});
				activePanel.setLayout(new BorderLayout(0, 0));
				
				JPanel activeStatusPanel = new JPanel();
				activePanel.add(activeStatusPanel, BorderLayout.WEST);
				activeStatusPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblActiveStatus = new JLabel("Status:");
				activeStatusPanel.add(lblActiveStatus, BorderLayout.WEST);
				
				JLabel lblActiveState = new JLabel(b.isActive()?"Active":"Not Active");
				activeStatusPanel.add(lblActiveState, BorderLayout.CENTER);
				activePanel.add(btnSetInactive, BorderLayout.EAST);
				
				panelAcquisition.add(inactivePanel, BorderLayout.SOUTH);
				inactivePanel.setLayout(new BorderLayout(5, 0));
				
				btnSetInactive.setVisible(b.getDeacquisition()==null);
				inactivePanel.setVisible((b.getDeacquisition()!=null)||!btnSetInactive.isEnabled());
				
				JPanel inactiveDatePanel = new JPanel();
				inactivePanel.add(inactiveDatePanel, BorderLayout.WEST);
				inactiveDatePanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblDeacquire = new JLabel("Date:");
				inactiveDatePanel.add(lblDeacquire, BorderLayout.WEST);
				
				txtDeacquireDate.setDate(refresh?txtDeacquireDate.getDate():b.getDeacquisition()!=null&&b.getDeacquisition().getDate()!=null?b.getDeacquisition().getDate():null);
				txtDeacquireDate.setEnabled(edit&&b.getDeacquisition()==null);
				
				inactiveDatePanel.add(txtDeacquireDate, BorderLayout.CENTER);
				
				JPanel inactiveMethodPanel = new JPanel();
				inactivePanel.add(inactiveMethodPanel);
				inactiveMethodPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblDeacquireBy = new JLabel("Inactive By:");
				inactiveMethodPanel.add(lblDeacquireBy, BorderLayout.WEST);
				
				JPanel inactiveMethodValuePanel = new JPanel();
				inactiveMethodPanel.add(inactiveMethodValuePanel);
				inactiveMethodValuePanel.setLayout(new BorderLayout(0, 0));
	
				final JPanel inactiveSoldPanel = new JPanel();

				if(b.getDeacquisition()!=null){
					JLabel lblDeacquireMethod = new JLabel(b.getDeacquisition()!=null?b.getDeacquisition().getMethod():"Unknown");
					inactiveMethodValuePanel.add(lblDeacquireMethod, BorderLayout.CENTER);
				}else{
					inactiveMethodValuePanel.add(lstDeacquireMethod, BorderLayout.CENTER);
					lstDeacquireMethod.addActionListener(new ActionListener(){
						@Override
						public void actionPerformed(ActionEvent e) {
							inactiveSoldPanel.setVisible(lstDeacquireMethod.getSelectedItem().equals("Sold"));
							sellPrice.setEnabled(edit&&b.getDeacquisition()==null);
							txtDeacquireDate.setEnabled(edit&&b.getDeacquisition()==null);
						}
					});
				}
				
				inactivePanel.add(inactiveSoldPanel, BorderLayout.SOUTH);
				inactiveSoldPanel.setLayout(new BoxLayout(inactiveSoldPanel,BoxLayout.X_AXIS));

				JPanel inactivePricePanel = new JPanel();
				inactiveSoldPanel.add(inactivePricePanel);
				inactivePricePanel.setBorder(new EmptyBorder(0,0,0,10));
				inactivePricePanel.setLayout(new BoxLayout(inactivePricePanel, BoxLayout.X_AXIS));

				inactivePricePanel.add(new JLabel("Price: $"));
				
				sellPrice.setEnabled(edit&&b.getDeacquisition()==null);
				sellPrice.setColumns(10);
				inactivePricePanel.add(sellPrice);
				sellPrice.setText(refresh?sellPrice.getText():b.getDeacquisition()!=null?String.valueOf(b.getDeacquisition().getPrice()):"0.00");
				
				JPanel inactiveOwnerPanel = new JPanel();
				inactiveSoldPanel.add(inactiveOwnerPanel);
				inactiveOwnerPanel.setLayout(new BorderLayout(0, 0));
				
				JLabel lblNewOwner = new JLabel("Sold to:");
				lblNewOwner.setHorizontalAlignment(SwingConstants.RIGHT);
				inactiveOwnerPanel.add(lblNewOwner,BorderLayout.WEST);
				
				if(b.getDeacquisition()!=null){
					final JButton btnNewOwner = new JButton(b.getDeacquisition()!=null&&b.getDeacquisition().getOwner()!=null?b.getDeacquisition().getOwner().getName():"Not Available");
					btnNewOwner.setEnabled(b.getDeacquisition()!=null&&b.getDeacquisition().getOwner()!=null);
					inactiveOwnerPanel.add(btnNewOwner,BorderLayout.CENTER);
					
					btnNewOwner.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							if(!MainFrame.getInstance().showOwner(b.getDeacquisition().getOwner().getID())){
								// Show Owner not found message?
								btnNewOwner.setEnabled(false);
							}
						}
					});
				}else{
					lstNewOwner.setEditable(true);
					inactiveOwnerPanel.add(lstNewOwner,BorderLayout.CENTER);
				}
				
				inactiveSoldPanel.setVisible(!((String)lstDeacquireMethod.getSelectedItem()).toLowerCase().equals("death")||b.getDeacquisition()!=null&&b.getDeacquisition().getOwner()!=null);
			}else{
				txtDeacquireDate.setDate("");
			}
			
			acquirePurchasePanel.setVisible(!((String)lstAcquireMethod.getSelectedItem()).toLowerCase().equals("birth")||b!=null&&b.getAcquisition()!=null&&!b.getAcquisition().getMethod().toLowerCase().equals("birth"));
			JPanel parentPanel = new JPanel();
			panelID.add(parentPanel, BorderLayout.SOUTH);
			parentPanel.setLayout(new BoxLayout(parentPanel, BoxLayout.X_AXIS));
			
			JPanel parentDamePanel = new JPanel();
			parentPanel.add(parentDamePanel);
			parentDamePanel.setBorder(new EmptyBorder(0,0,0,10));
			parentDamePanel.setLayout(new BorderLayout(5, 0));
			
			JLabel lblDame = new JLabel("Dame:");
			parentDamePanel.add(lblDame, BorderLayout.WEST);
			
			JPanel damePanel = new JPanel();
			parentDamePanel.add(damePanel, BorderLayout.CENTER);
			damePanel.setLayout(new BorderLayout(5, 0));
			
			if(b!=null&&b.getDob()!=null&&!b.getGender().equals(Bovine.GENDER)||!edit){
				final JButton btnDame = new JButton(b!=null&&b.getDame()!=null?b.getDame().getEartag().getEartagID()+" - "+b.getDame().getEartag().getRfID():"Not Available");
				damePanel.add(btnDame, BorderLayout.CENTER);
				if(b!=null){
					btnDame.setEnabled(b.getDame()!=null);
					btnDame.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							if(!MainFrame.getInstance().showBovine(b.getDame().getID())){
								//Show message not found?
								btnDame.setEnabled(false);
							}
						}
					});
				}else{
					btnDame.setEnabled(false);
				}
			}else{
				damePanel.add(lstDame, BorderLayout.CENTER);
				selectedObject = lstDame.getSelectedItem();
				lstDame.setModel(new DefaultComboBoxModel(cowList.toArray()));
				lstDame.setEnabled(b!=null&&b.getDame()==null||b==null);
				if(selectedObject==null){
					if(dameSelected<lstDame.getItemCount()){
						lstDame.setSelectedIndex(dameSelected);
					}
				}else{
					lstDame.setSelectedItem(selectedObject);
				}
			}
			
			JPanel parentSirePanel = new JPanel();
			parentPanel.add(parentSirePanel);
			parentSirePanel.setLayout(new BorderLayout(5, 0));
			
			JLabel lblSire = new JLabel("Sire:");
			parentSirePanel.add(lblSire, BorderLayout.WEST);
			
			JPanel sirePanel = new JPanel();
			parentSirePanel.add(sirePanel, BorderLayout.CENTER);
			sirePanel.setLayout(new BorderLayout(0, 0));
			
			if(b!=null&&b.getDob()!=null&&!b.getGender().equals(Bovine.GENDER)||!edit){
				final JButton btnSire = new JButton(b!=null&&b.getSire()!=null?b.getSire().getEartag().getEartagID()+" - "+b.getSire().getEartag().getRfID():"Not Available");
				if(b!=null){
					btnSire.setEnabled(b.getSire()!=null);
					btnSire.addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent e) {
							if(!MainFrame.getInstance().showBovine(b.getSire().getID())){
								//Show message not found?
								btnSire.setEnabled(false);
							}
						}
					});
				}else{
					btnSire.setEnabled(false);
				}
				sirePanel.add(btnSire, BorderLayout.CENTER);
			}else{
				sirePanel.add(lstSire, BorderLayout.CENTER);
				selectedObject = lstSire.getSelectedItem();
				lstSire.setModel(new DefaultComboBoxModel(bullList.toArray()));
				lstSire.setEnabled(b!=null&&b.getSire()==null||b==null);
				if(selectedObject==null){
					if(sireSelected<lstSire.getItemCount()){
						lstSire.setSelectedIndex(sireSelected);
					}
				}else{
					lstSire.setSelectedItem(selectedObject);
				}
			}

			if(viewing == VIEW_OFFSPRING){
				jisp.setSelectedComponent(offspringListPanel);
				createOffspringPanel(bovineID);
			}else if(viewing == VIEW_JOINING){
				jisp.setSelectedComponent(joiningListPanel);
				createJoiningsPanel(bovineID);
			}else if(viewing == VIEW_FEEDS){
				jisp.setSelectedComponent(feedsListPanel);
				createFeedPanel(bovineID);
			}else if(viewing == VIEW_MEDICALS){
				jisp.setSelectedComponent(vetVisitsListPanel);
				createMedicalPanel(bovineID);
			}else if(viewing == VIEW_MEDICINES){
				jisp.setSelectedComponent(medicinesListPanel);
				createMedicinePanel(bovineID);
			}else if(viewing == VIEW_WEIGHINGS){
				jisp.setSelectedComponent(weighingsListPanel);
				createWeightsPanel(bovineID);
			}else if(viewing == VIEW_GROUPS && jisp.indexOfComponent(groupsListPanel)>=0){
				jisp.setSelectedComponent(groupsListPanel);
				createGroupsPanel(bovineID);
			}else if(viewing == VIEW_OBSERVATION || viewing == VIEW){
				jisp.setSelectedComponent(observationsListPanel);
				createObservationsPanel(bovineID);
			}
		}else{
			panel.removeAll();
			panel.setLayout(new BorderLayout(10, 10));

			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Animal can be found with the given internal id: "+bovineID);
			flow.add(label);
			panel.add(flow, BorderLayout.NORTH);
			return false;
		}
		validate();
		
		return true;
	}
	
	/**
	 * Create a list of observations that belong to this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the Observations for.
	 */
	private void createObservationsPanel(final long bovineID){
		viewing = VIEW_OBSERVATION;
		observationsListPanel.setLayout(new BorderLayout());
		
		final int DATE 		= 0;
		final int DESCRIPTION 	= 1;
		final int PRIORITY 	= 2;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		
		final Table observationPanel = new Table("Observations",false,
			"Date","Description","Priority");
		observationPanel.setEmptyMessage("There are no observations to show.");
		
		new Thread(){
			@Override
			public void run(){
				observationPanel.setHeaderClickable(DESCRIPTION, false);
				observationPanel.setHeaderOrderedBy(orderObservationListBy==LIST_ORDER_DATE?DATE:orderObservationListBy==LIST_ORDER_PRIORITY?PRIORITY:DATE, orderObservationHighToLow==1);
				observationPanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_DATE?-1:1);
						orderObservationListBy = LIST_ORDER_DATE;
						createObservationsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				observationPanel.addHeaderMouseListener(PRIORITY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderObservationHighToLow = orderObservationHighToLow*(orderObservationListBy==LIST_ORDER_PRIORITY?-1:1);
						orderObservationListBy = LIST_ORDER_PRIORITY;
						createObservationsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Observation[] oList = b!=null?b.getObservations():new Observation[]{};
				
				Arrays.sort(oList, 
					orderObservationListBy==LIST_ORDER_DATE?
							orderObservationHighToLow==1?Comparators.observationComparatorDate:Collections.reverseOrder(Comparators.observationComparatorDate)
					:orderObservationHighToLow==1?Comparators.observationComparatorPriority:Collections.reverseOrder(Comparators.observationComparatorPriority));

				for(int x=0; x<oList.length; x++){
					observationPanel.addRow(
						new JLabel(JDatePickerDate.format(oList[x].getDate())),
						new JLabel(oList[x].getComment()),
						new JLabel(Observation.getPriorityString(oList[x].getPriority())));
					
					final Observation o = oList[x];
					
					observationPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new ObservationFrame(b,o,(b instanceof Cow?"Cow":(b instanceof Bull?"Bull":"Cattle"))+" with visual ID: "+b.getEartag().getEartagID()).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_OBSERVATION && bovineViewID==bovineID){
										createObservationsPanel(bovineID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();
		
		// Allow up to two months to allow a possible bovine to be the parents of a new offspring.
		Calendar ca = Calendar.getInstance();
		ca.add(Calendar.DATE, b!=null?b.getBreed().getGestationPeriodInDays()+60:+0);
		final JButton btnAddObservation = new JButton("Add Observation");
		btnAddObservation.setEnabled(b!=null&&(b.isActive()||b.getDeacquisition()!=null&&b.getDeacquisition()!=null&&b.getDeacquisition().getDate()!=null&&b.getDeacquisition().getDate().before(ca.getTime())));
		btnAddObservation.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				new ObservationFrame(b,null,(b instanceof Cow?"Cow":(b instanceof Bull?"Bull":"Cattle"))+" with visual ID: "+b.getEartag().getEartagID()).addWindowListener(new WindowListener(){
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_OBSERVATION && BovinePanel.this.bovineViewID==bovineViewID){
							createObservationsPanel(bovineViewID);
						}
					}
					@Override public void windowOpened(WindowEvent e) {}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
				observationPanel.addRow(null,new JLabel("<New Observation>"),null);
				btnAddObservation.setEnabled(false);
				observationPanel.validate();
				panel.validate();
			}
		});
		
		observationsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddObservation);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(observationPanel,BorderLayout.CENTER);
		observationsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();

		jisp.setSelectedComponent(observationsListPanel);
	}
	
	/**
	 * Create a list of offspring that belong to this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the Members for.
	 */
	private void createOffspringPanel(final long bovineID){
		viewing = VIEW_OFFSPRING;
		offspringListPanel.setLayout(new BorderLayout());
		
		final JPanel offspringPanelFrame = new JPanel();
		offspringPanelFrame.setLayout(new BorderLayout(0, 0));
		
		final int ADD		= 0;
		final int VISUAL	= 1;
		final int NLIS		= 2;
		final int RF		= 3;
		final int DOB 		= 4;
		final int ACTIVE	= 5;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);

		final Table bovinePanel = new Table("Offspring",false,
			"","Visual ID","NLIS","RF ID","DOB","Status");
		bovinePanel.setEmptyMessage("There are no Offspring to show.");
		// Hide the first column (add or remove column) as an Offspring can not be removed from the parent.
		bovinePanel.setColumnVisible(ADD, false);
		
		final Table bovineAddPanel = new Table("Offspring",false,
			"Add as Offspring","Visual ID","NLIS","RF ID","DOB","Status");
		bovineAddPanel.setEmptyMessage("There are no eligible offspring to show.");
		
		new Thread(){
			@Override
			public void run(){
				MouseListener vi = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderOffspringHighToLow = orderOffspringHighToLow*(orderOffspringListBy==LIST_ORDER_VISUAL?-1:1);
						orderOffspringListBy = LIST_ORDER_VISUAL;
						createOffspringPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				MouseListener rf = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderOffspringHighToLow = orderOffspringHighToLow*(orderOffspringListBy==LIST_ORDER_RF?-1:1);
						orderOffspringListBy = LIST_ORDER_RF;
						createOffspringPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				MouseListener nl = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderOffspringHighToLow = orderOffspringHighToLow*(orderOffspringListBy==LIST_ORDER_NLIS?-1:1);
						orderOffspringListBy = LIST_ORDER_NLIS;
						createOffspringPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				MouseListener dob = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderOffspringHighToLow = orderOffspringHighToLow*(orderOffspringListBy==LIST_ORDER_DOB?-1:1);
						orderOffspringListBy = LIST_ORDER_DOB;
						createOffspringPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				MouseListener ac = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderOffspringHighToLow = orderOffspringHighToLow*(orderOffspringListBy==LIST_ORDER_ACTIVE?-1:1);
						orderOffspringListBy = LIST_ORDER_ACTIVE;
						createOffspringPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				
				bovinePanel.setHeaderOrderedBy(orderOffspringListBy==LIST_ORDER_VISUAL?VISUAL:orderOffspringListBy==LIST_ORDER_RF?RF:orderOffspringListBy==LIST_ORDER_NLIS?NLIS:orderOffspringListBy==LIST_ORDER_DOB?DOB:orderOffspringListBy==LIST_ORDER_ACTIVE?ACTIVE:VISUAL, orderOffspringHighToLow==1);
				bovinePanel.addHeaderMouseListener(VISUAL, vi);
				bovinePanel.addHeaderMouseListener(RF, rf);
				bovinePanel.addHeaderMouseListener(NLIS, nl);
				bovinePanel.addHeaderMouseListener(DOB, dob);
				bovinePanel.addHeaderMouseListener(ACTIVE, ac);
				
				Bovine[] bList = b!=null?b.getOffspring():new Bovine[]{};
				
				Arrays.sort(bList, 
					orderOffspringListBy==LIST_ORDER_VISUAL?
						orderOffspringHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
					:orderOffspringListBy==LIST_ORDER_NLIS?
						orderOffspringHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
					:orderOffspringListBy==LIST_ORDER_RF?
						orderOffspringHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
					:orderOffspringListBy==LIST_ORDER_DOB?
						orderOffspringHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
					:orderOffspringHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));

				for(int x=0; x<bList.length; x++){
					bovinePanel.addRow(
						null,
						new JLabel(bList[x].getEartag().getEartagID()),
						new JLabel(bList[x].getEartag().getNlisID()),
						new JLabel(bList[x].getEartag().getRfID()),
						new JLabel(bList[x].getDob()!=null?JDatePickerDate.format(bList[x].getDob()):"Unknown"),
						new JLabel(bList[x].isActive()?"Active":bList[x].getDeacquisition().getMethod()));
				
					final long id = bList[x].getID();
					bovinePanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(!MainFrame.getInstance().showBovine(id)){
								//Show message not found?
							}
						}
						@Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {}
					});
				}
				
				if(b!=null&&edit){
					bovineAddPanel.setHeaderOrderedBy(orderOffspringListBy==LIST_ORDER_VISUAL?VISUAL:orderOffspringListBy==LIST_ORDER_RF?RF:orderOffspringListBy==LIST_ORDER_NLIS?NLIS:orderOffspringListBy==LIST_ORDER_DOB?DOB:orderOffspringListBy==LIST_ORDER_ACTIVE?ACTIVE:VISUAL, orderOffspringHighToLow==1);
					bovineAddPanel.setHeaderClickable(ADD, false);
					bovineAddPanel.addHeaderMouseListener(VISUAL, vi);
					bovineAddPanel.addHeaderMouseListener(RF, rf);
					bovineAddPanel.addHeaderMouseListener(NLIS, nl);
					bovineAddPanel.addHeaderMouseListener(DOB, dob);
					bovineAddPanel.addHeaderMouseListener(ACTIVE, ac);
	
					ArrayList<Bovine> bTList = new ArrayList<Bovine>(Arrays.asList(LivestockSolutions.getBovines()));
					Iterator<Bovine> i = bTList.iterator();
					ArrayList<Bovine> trace = new ArrayList<Bovine>();
					if(b!=null){
						trace = getParents(trace,b);
						while(i.hasNext()){
							Bovine ob = i.next();
							if(trace.contains(ob)||ob.getID()==b.getID()||(ob.getDob()!=null&&b.getDob()!=null&&!ob.getDob().after(b.getDob())||(b.getGender().equals(Cow.GENDER)&&ob.getDame()!=null)||(b.getGender().equals(Bull.GENDER)&&ob.getSire()!=null))){
								i.remove();
							}
						}
					}
					Bovine[] bAList =bTList.toArray(new Bovine[]{});
					Arrays.sort(bAList, 
						orderOffspringListBy==LIST_ORDER_VISUAL?
							orderOffspringHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
						:orderOffspringListBy==LIST_ORDER_NLIS?
							orderOffspringHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
						:orderOffspringListBy==LIST_ORDER_RF?
							orderOffspringHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
						:orderOffspringListBy==LIST_ORDER_DOB?
							orderOffspringHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
						:orderOffspringHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));
	
					for(int x=0; x<bAList.length; x++){
						final JCheckBox add = new JCheckBox();
						// Set this Animal to selected if it is currently selected.
						add.setSelected(bovineOffspringAddList.contains(bAList[x]));
						final int bovinePanelIndex=bovineAddPanel.getNumRows();
						final Bovine offspring = bAList[x];
						bovineAddPanel.addRow(
							add,
							new JLabel(bAList[x].getEartag().getEartagID()),
							new JLabel(bAList[x].getEartag().getNlisID()),
							new JLabel(bAList[x].getEartag().getRfID()),
							new JLabel(bAList[x].getDob()!=null?JDatePickerDate.format(bAList[x].getDob()):"Unknown"),
							new JLabel(bAList[x].isActive()?"Active":bAList[x].getDeacquisition().getMethod()));
						bovineAddPanel.setSelected(add.isSelected());
						bovineAddPanel.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								add.setSelected(!add.isSelected());
								bovineAddPanel.setSelected(bovinePanelIndex,add.isSelected());
								if(add.isSelected()){
									bovineOffspringAddList.add(offspring);
								}else{
									bovineOffspringAddList.remove(offspring);
								}
							}
							@Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {}
						});
						
						bovineAddPanel.addDefaultMouseListenerTo(add);
						add.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								bovineAddPanel.setSelected(bovinePanelIndex,add.isSelected());
								if(add.isSelected()){
									bovineOffspringAddList.add(offspring);
								}else{
									bovineOffspringAddList.remove(offspring);
								}
							}
							@Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {}
						});
					}
					JButton newJoining = new JButton("New Offspring");
					newJoining.addActionListener(new ActionListener(){
						@Override
						public void actionPerformed(ActionEvent arg0) {
							MainFrame.getInstance().showBovine(-1, b);
						}
					});
					JPanel topPanelSelection = new JPanel();
					topPanelSelection.setLayout(new BorderLayout(0, 0));
					JPanel flow =new JPanel();
					JLabel label = new JLabel("<html><body>Select an existing animal,<br> or choose to create a new Offspring.</body></html>");
					flow.add(label);
					topPanelSelection.add(flow, BorderLayout.WEST);
					topPanelSelection.add(newJoining,BorderLayout.EAST);
					offspringPanelFrame.add(topPanelSelection, BorderLayout.NORTH);
					offspringPanelFrame.add(bovineAddPanel, BorderLayout.CENTER);
				}
				validate();
			}
		}.start();

		JButton btnAddOffspring = new JButton("Add Offspring");
		Calendar ca = Calendar.getInstance();
		// Allow up to two months to allow a possible bovine to be the parents of a new offspring.
		ca.add(Calendar.DATE, b!=null?b.getBreed().getGestationPeriodInDays()+60:0);
		btnAddOffspring.setEnabled(!edit&&b!=null&&(!b.getGender().equals(Bovine.GENDER)&&(b.isActive()||b.getDeacquisition()!=null&&b.getDeacquisition().getDate()!=null&&b.getDeacquisition().getDate().before(ca.getTime()))));
		btnAddOffspring.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=true;
				createBovinePanel(bovineID);
			}
		});
		if(b==null || b.getGender().equals(Bovine.GENDER)){
			btnAddOffspring.setToolTipText("The Gender of this animal must be something other than "+Bovine.GENDER+" to be able to add Offspring");
		}
		
		offspringListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddOffspring);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(bovinePanel,BorderLayout.CENTER);
		container.add(offspringPanelFrame, BorderLayout.SOUTH);
		offspringListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
		
		jisp.setSelectedComponent(offspringListPanel);
	}
	
	/**
	 * Create a list of Groups that this Bovine belongs to.
	 * @param bovineID The long ID value that represents the Bovine to show the Groups for.
	 */
	private void createGroupsPanel(final long bovineID){
		viewing = VIEW_GROUPS;
		groupsListPanel.setLayout(new BorderLayout());
		
		final JPanel groupPanelFrame = new JPanel();
		groupPanelFrame.setLayout(new BorderLayout(0, 0));
	
		final int INCLUDE 		= 0;
		final int NAME 			= 1;
		final int DESCRIPTION	= 2;
		final int COUNT			= 3;

		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		
		final Table groupPanel = new Table("Groups",false,
			"In Group","Name","Description","No. Members");
		groupPanel.setEmptyMessage("There are no Groups to show.");
		
		final Table groupAddPanel = new Table("Groups",false,
				"In Group","Name","Description","No. Members");
		groupAddPanel.setEmptyMessage("There are no Groups to show.");
		
		new Thread(){
			@Override
			public void run(){
				MouseListener na = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderGroupHighToLow = orderGroupHighToLow*(orderGroupListBy==LIST_ORDER_NAME?-1:1);
						orderGroupListBy = LIST_ORDER_NAME;
						createGroupsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				MouseListener co = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderGroupHighToLow = orderGroupHighToLow*(orderGroupListBy==LIST_ORDER_COUNT?-1:1);
						orderGroupListBy = LIST_ORDER_COUNT;
						createGroupsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				
				groupPanel.setHeaderClickable(INCLUDE, false);
				groupPanel.setHeaderClickable(DESCRIPTION, false);
				groupPanel.setHeaderOrderedBy(orderGroupListBy==LIST_ORDER_NAME?NAME:orderGroupListBy==LIST_ORDER_COUNT?COUNT:NAME, orderGroupHighToLow==1);
				groupPanel.addHeaderMouseListener(NAME, na);
				groupPanel.addHeaderMouseListener(COUNT, co);
				Group[] gList = b!=null?LivestockSolutions.getBovineByID(bovineID).getGroups():new Group[]{};
				Arrays.sort(gList, 
					orderGroupListBy==LIST_ORDER_NAME?
						orderGroupHighToLow==1?Comparators.groupComparatorName:Collections.reverseOrder(Comparators.groupComparatorName)
					:orderGroupHighToLow==1?Comparators.groupComparatorCount:Collections.reverseOrder(Comparators.groupComparatorCount));

				for(int x=0; x<gList.length; x++){
					final JCheckBox add = new JCheckBox();
					// Set this Animal to selected if it is in the Group filter list.
					add.setSelected(!bovineGroupAddList.contains(gList[x]));
					add.setEnabled(edit);
					final int groupPanelIndex=groupPanel.getNumRows();
					groupPanel.addRow(
						add,
						new JLabel(gList[x].getName()),
						new JLabel(gList[x].getDescription()),
						new JLabel(String.valueOf(gList[x].getBovineList().length)));
					
					groupPanel.setSelected(edit&&add.isSelected());
					final Group g = gList[x];
					groupPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(!edit){
								if(!MainFrame.getInstance().showGroup(g.getID())){
									//Show message not found?
								}
							}else{
								add.setSelected(!add.isSelected());
								groupPanel.setSelected(groupPanelIndex, add.isSelected());
								if(!add.isSelected()){
									bovineGroupAddList.add(g);
								}else{
									bovineGroupAddList.remove(g);
								}
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					
					groupPanel.addDefaultMouseListenerTo(add);
					add.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(!edit){
								if(!MainFrame.getInstance().showGroup(g.getID())){
									//Show message not found?
								}
							}else{
								groupPanel.setSelected(groupPanelIndex, add.isSelected());
								if(!add.isSelected()){
									bovineGroupAddList.add(g);
								}else{
									bovineGroupAddList.remove(g);
								}
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				
				if(b!=null&&edit){
					groupAddPanel.setHeaderClickable(INCLUDE, false);
					groupAddPanel.setHeaderClickable(DESCRIPTION, false);
					groupAddPanel.setHeaderOrderedBy(orderGroupListBy==LIST_ORDER_NAME?NAME:orderGroupListBy==LIST_ORDER_COUNT?COUNT:NAME, orderGroupHighToLow==1);
					groupAddPanel.addHeaderMouseListener(NAME, na);
					groupAddPanel.addHeaderMouseListener(COUNT, co);
					
					ArrayList<Group> gTList = new ArrayList<Group>(Arrays.asList(LivestockSolutions.getOnlyGroups()));
					if(b!=null){
						Iterator<Group> i = gTList.iterator();
						while(i.hasNext()){
							Group g = i.next();
							if(Arrays.asList(b.getGroups()).contains(g)){
								i.remove();
							}
						}
					}
					
					Group[] gAList = gTList.toArray(new Group[]{});
					Arrays.sort(gAList, 
						orderGroupListBy==LIST_ORDER_NAME?
							orderGroupHighToLow==1?Comparators.groupComparatorName:Collections.reverseOrder(Comparators.groupComparatorName)
						:orderGroupHighToLow==1?Comparators.groupComparatorCount:Collections.reverseOrder(Comparators.groupComparatorCount));
					
					for(int x=0; x<gAList.length; x++){
						final JCheckBox add = new JCheckBox();
						// Set this Animal to selected if it is in the Group filter list.
						add.setSelected(bovineGroupAddList.contains(gAList[x]));
						add.setEnabled(edit);
						final int groupPanelIndex=groupAddPanel.getNumRows();
						groupAddPanel.addRow(
							add,
							new JLabel(gAList[x].getName()),
							new JLabel(gAList[x].getDescription()),
							new JLabel(String.valueOf(gAList[x].getBovineList().length)));
						groupAddPanel.setSelected(add.isSelected());
						final Group g = gAList[x];
						groupAddPanel.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								add.setSelected(!add.isSelected());
								groupAddPanel.setSelected(groupPanelIndex,add.isSelected());
								if(add.isSelected()){
									bovineGroupAddList.add(g);
								}else{
									bovineGroupAddList.remove(g);
								}
							}
							@Override public void mousePressed(MouseEvent e) {}
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
						
						groupAddPanel.addDefaultMouseListenerTo(add);
						add.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								groupAddPanel.setSelected(groupPanelIndex,add.isSelected());
								if(add.isSelected()){
									bovineGroupAddList.add(g);
								}else{
									bovineGroupAddList.remove(g);
								}
							}
							@Override public void mousePressed(MouseEvent e) {}
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
					}
					groupPanelFrame.setVisible(edit);
					
					JButton newGroup = new JButton("New Group");
					newGroup.addActionListener(new ActionListener(){
						@Override
						public void actionPerformed(ActionEvent arg0) {
							MainFrame.getInstance().showGroup(-1, b);
						}
					});
					JPanel topPanelSelection = new JPanel();
					topPanelSelection.setLayout(new BorderLayout(0, 0));
					JPanel flow =new JPanel();
					JLabel label = new JLabel("<html><body>Select an existing group,<br> or choose to create a new group.</body></html>");
					flow.add(label);
					topPanelSelection.add(flow, BorderLayout.WEST);
					topPanelSelection.add(newGroup,BorderLayout.EAST);
					groupPanelFrame.add(topPanelSelection, BorderLayout.NORTH);
					groupPanelFrame.add(groupAddPanel, BorderLayout.CENTER);
				}
				validate();
			}
		}.start();
			
		final JButton btnAddGroup = new JButton("Add to Group");
		btnAddGroup.setEnabled(!edit&&b!=null);
		btnAddGroup.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=true;
				createBovinePanel(bovineID);
			}
		});
		
		groupsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddGroup);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(groupPanel,BorderLayout.CENTER);
		container.add(groupPanelFrame,BorderLayout.SOUTH);
		groupsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
		
		jisp.setSelectedComponent(groupsListPanel);
	}
	
	/**
	 * Create a list of joinings that belong to this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the Joinings for.
	 */
	private void createJoiningsPanel(final long bovineID){
		viewing = VIEW_JOINING;
		joiningListPanel.setLayout(new BorderLayout());
		
		final JPanel joiningPanelFrame = new JPanel();
		joiningPanelFrame.setLayout(new BorderLayout(0, 0));
		
		final int BULL_IN 	= 0;
		final int BULL_OUT	= 1;
		final int BULL 		= 2;
		final int COUNT		= 3;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		
		final Table joiningPanel = new Table("Joinings",false,
			"Bull Entry Date","Bull Exit Date","Bull Visual ID","No. Members");
		joiningPanel.setEmptyMessage("There are no Joinings to show.");
		
		final Table joiningAddPanel = new Table("Joinings",false,
				"Bull Entry Date","Bull Exit Date","Bull Visual ID","No. Members");
			joiningAddPanel.setEmptyMessage("There are no Joinings to show.");
		
		new Thread(){
			@Override
			public void run(){
				
				MouseListener bi = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_ENTRY?-1:1);
						orderJoiningListBy = LIST_ORDER_ENTRY;
						createJoiningsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				
				MouseListener bo = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_EXIT?-1:1);
						orderJoiningListBy = LIST_ORDER_EXIT;
						createJoiningsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				
				MouseListener bu = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_BULL?-1:1);
						orderJoiningListBy = LIST_ORDER_BULL;
						createJoiningsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				
				MouseListener co = new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_COW_COUNT?-1:1);
						orderJoiningListBy = LIST_ORDER_COW_COUNT;
						createJoiningsPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				};
				
				joiningPanel.setHeaderOrderedBy(orderJoiningListBy==LIST_ORDER_ENTRY?BULL_IN:orderJoiningListBy==LIST_ORDER_EXIT?BULL_OUT:orderJoiningListBy==LIST_ORDER_BULL?BULL:orderJoiningListBy==LIST_ORDER_COW_COUNT?COUNT:BULL_IN, orderJoiningHighToLow==1);
				joiningPanel.addHeaderMouseListener(BULL_IN, bi);
				joiningPanel.addHeaderMouseListener(BULL_OUT, bo);
				joiningPanel.addHeaderMouseListener(BULL, bu);
				joiningPanel.addHeaderMouseListener(COUNT, co);

				Join[] jList = b!=null?b.getJoinings():new Join[]{};
				
				Arrays.sort(jList, 
					orderJoiningListBy==LIST_ORDER_ENTRY?
						orderJoiningHighToLow==1?Comparators.joiningComparatorEntry:Collections.reverseOrder(Comparators.joiningComparatorEntry)
					:orderJoiningListBy==LIST_ORDER_EXIT?
						orderJoiningHighToLow==1?Comparators.joiningComparatorExit:Collections.reverseOrder(Comparators.joiningComparatorExit)
					:orderJoiningListBy==LIST_ORDER_BULL?
						orderJoiningHighToLow==1?Comparators.joiningComparatorBull:Collections.reverseOrder(Comparators.joiningComparatorBull)
					:orderJoiningHighToLow==1?Comparators.joiningComparatorCowCount:Collections.reverseOrder(Comparators.joiningComparatorCowCount));

				for(int x=0; x<jList.length; x++){
					joiningPanel.addRow(
						new JLabel(JDatePickerDate.format(jList[x].getInsertionDate())),
						new JLabel(jList[x].getRemovalDate()!=null?JDatePickerDate.format(jList[x].getRemovalDate()):"Still Active"),
						new JLabel(jList[x].getBull().getEartag().getEartagID()),
						new JLabel(jList[x].getCows()!=null?String.valueOf(jList[x].getCows().length):"0"));
					
					final long id = jList[x].getID();
					joiningPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(MainFrame.getInstance().showJoining(id)){
								//Show message not found?
							}
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				
				if(b!=null&&edit){
					joiningAddPanel.setHeaderOrderedBy(orderJoiningListBy==LIST_ORDER_ENTRY?BULL_IN:orderJoiningListBy==LIST_ORDER_EXIT?BULL_OUT:orderJoiningListBy==LIST_ORDER_BULL?BULL:orderJoiningListBy==LIST_ORDER_COW_COUNT?COUNT:BULL_IN, orderJoiningHighToLow==1);
					joiningAddPanel.addHeaderMouseListener(BULL_IN, bi);
					joiningAddPanel.addHeaderMouseListener(BULL_OUT, bo);
					joiningAddPanel.addHeaderMouseListener(BULL, bu);
					joiningAddPanel.addHeaderMouseListener(COUNT, co);
	
					ArrayList<Join> jTList = new ArrayList<Join>(Arrays.asList(LivestockSolutions.getJoinings()));
					Iterator<Join> i = jTList.iterator();
					while(i.hasNext()){
						Join j = i.next();
						if(Arrays.asList(j.getCows()).contains(b)||j.getRemovalDate()!=null){
							i.remove();
						}
					}
					Join[] jAList =jTList.toArray(new Join[]{});
					Arrays.sort(jAList, 
						orderJoiningListBy==LIST_ORDER_ENTRY?
							orderJoiningHighToLow==1?Comparators.joiningComparatorEntry:Collections.reverseOrder(Comparators.joiningComparatorEntry):
						orderJoiningListBy==LIST_ORDER_EXIT?
							orderJoiningHighToLow==1?Comparators.joiningComparatorExit:Collections.reverseOrder(Comparators.joiningComparatorExit):
						orderJoiningListBy==LIST_ORDER_BULL?
							orderJoiningHighToLow==1?Comparators.joiningComparatorBull:Collections.reverseOrder(Comparators.joiningComparatorBull):
							orderJoiningHighToLow==1?Comparators.joiningComparatorCowCount:Collections.reverseOrder(Comparators.joiningComparatorCowCount));
					
					for(int x=0; x<jAList.length; x++){
						joiningAddPanel.addRow(
							new JLabel(JDatePickerDate.format(jAList[x].getInsertionDate())),
							new JLabel(jAList[x].getRemovalDate()!=null?JDatePickerDate.format(jAList[x].getRemovalDate()):"Still Active"),
							new JLabel(jAList[x].getBull().getEartag().getEartagID()),
							new JLabel(jAList[x].getCows()!=null?String.valueOf(jAList[x].getCows().length):"0"));
						
						final long id = jAList[x].getID();
						joiningAddPanel.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								if(MainFrame.getInstance().showJoining(id, b)){
									//Show message not found?
								}
							}
							@Override public void mousePressed(MouseEvent e) { }
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
					}
					JButton newJoining = new JButton("New Joining");
					newJoining.addActionListener(new ActionListener(){
						@Override
						public void actionPerformed(ActionEvent arg0) {
							MainFrame.getInstance().showJoining(-1, b);
						}
					});
					JPanel topPanelSelection = new JPanel();
					topPanelSelection.setLayout(new BorderLayout(0, 0));
					JPanel flow =new JPanel();
					JLabel label = new JLabel("<html><body>Select an existing Joining,<br>or choose to create a new Joining to add this animal to.</body></html>");
					flow.add(label);
					topPanelSelection.add(flow, BorderLayout.WEST);
					topPanelSelection.add(newJoining,BorderLayout.EAST);
					joiningPanelFrame.add(topPanelSelection, BorderLayout.NORTH);
					joiningPanelFrame.add(joiningAddPanel, BorderLayout.CENTER);
				}
				validate();
			}
		}.start();

		JButton btnAddJoining = new JButton("Add Joining");
		Calendar ca = Calendar.getInstance();
		// Allow up to two months to allow a possible bovine to be the parents of a new offspring.
		ca.add(Calendar.DATE, b!=null?b.getBreed().getGestationPeriodInDays()+60:0);
		btnAddJoining.setEnabled(!edit&&b!=null&&(!b.getGender().equals(Bovine.GENDER)&&b.isActive()));
		
		btnAddJoining.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if(b.getGender().equals(Bull.GENDER)){
					// Create a new Joining
					MainFrame.getInstance().showJoining(-1, b);
				}else{
					edit=true;
					createBovinePanel(bovineID);
				}
			}
		});
		if(b==null || b.getGender().equals(Bovine.GENDER)){
			btnAddJoining.setToolTipText("The Gender of this animal must be something other than "+Bovine.GENDER+" to be able to add a Joining");
		}
		
		joiningListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddJoining);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(joiningPanel,BorderLayout.CENTER);
		container.add(joiningPanelFrame,BorderLayout.SOUTH);
		joiningListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
		
		jisp.setSelectedComponent(joiningListPanel);
	}
	
	/**
	 * Create and display a list of weights that have been measured for this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the Weighings for.
	 */
	private void createWeightsPanel(final long bovineID){
		viewing = VIEW_WEIGHINGS;
		weighingsListPanel.setLayout(new BorderLayout());

		final int DATE	 		= 0;
		final int WEIGHT 		= 1;
		final int GAIN 			= 2;
		final int DAILY_GAIN 	= 3;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		
		final Table weighingPanel = new Table("Weighings",false,
			"Date","Weight","Weight Gain","Daily Weight Gain");
		weighingPanel.setEmptyMessage("There are no Weighings to show.");
		
		new Thread(){
			@Override
			public void run(){
				weighingPanel.setHeaderOrderedBy(DATE, true);
				weighingPanel.setHeaderClickable(DATE, false);
				weighingPanel.setHeaderClickable(WEIGHT, false);
				weighingPanel.setHeaderClickable(GAIN, false);
				weighingPanel.setHeaderClickable(DAILY_GAIN, false);
				
				if(b!=null){
					Weight[] wList = b.getWeighings();
					Arrays.sort(wList, Comparators.weighingComparatorDate);
					for(int x=0; x<wList.length; x++){
						weighingPanel.addRow(
							new JLabel(JDatePickerDate.format(wList[x].getDate())),
							new JLabel(String.valueOf(wList[x].getWeight())),
							new JLabel(String.valueOf(new DecimalFormat("#.###").format(wList[x].getWeight()-(x<=0?b.getBreed().getAverageCalfBirthWeight():wList[x-1].getWeight())))),
							new JLabel(x==0&&b.getDob()==null?"N/A":String.valueOf(new DecimalFormat("#.###").format((wList[x].getWeight()-(x<=0?b.getBreed().getAverageCalfBirthWeight():wList[x-1].getWeight()))/((wList[x].getDate().getTime()-(x<=0&&b.getDob()!=null?b.getDob().getTime():wList[x-1].getDate().getTime()))/1000/60/60/24)))));
					}
				}
				validate();
			}
		}.start();

		final JButton btnAddWeighing = new JButton("Add Weighing");
		btnAddWeighing.setEnabled(b!=null);
		btnAddWeighing.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				createWeightsPanel(bovineViewID);
				class WeightFrame extends JFrame{
					private static final long serialVersionUID = 1L;
					/**
					 * Constructor
					 */
					public WeightFrame(){
						setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
					}
					/**
					 * Create the Frame that contains a Date space and a weight text field.
					 */
					public void init(){
						JLabel label = new JLabel("Add a new weighing to \""+b.getEartag().getEartagID()+"\"");
						setTitle(label.getText());
						final JButton create = new JButton("Save");
						final JDatePickerDate dtpkrDate = JDatePickerDate.createJDatePicker();
						final JTextField weight = new JTextField();
						((AbstractDocument)weight.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
						create.addActionListener(new ActionListener(){
							@Override
							public void actionPerformed(ActionEvent arg0) {
								Calendar ca = Calendar.getInstance();
								ca.set(Calendar.DATE, dtpkrDate.getModel().getDay());
								ca.set(Calendar.MONTH, dtpkrDate.getModel().getMonth());
								ca.set(Calendar.YEAR, dtpkrDate.getModel().getYear());
								b.addWeighing(new Weight(ca.getTime(),Double.parseDouble(weight.getText())));
								createWeightsPanel(bovineViewID);
								dispose();
							}
						});
						
						JPanel panel = new JPanel();
						panel.setBorder(new EmptyBorder(5,5,5,5));
						getContentPane().add(panel, BorderLayout.NORTH);
						panel.setLayout(new BorderLayout(5, 0));
						
						JPanel flow =new JPanel();
						flow.add(label);
						panel.add(flow, BorderLayout.NORTH);
						
						JPanel datePanel = new JPanel();
						panel.add(datePanel, BorderLayout.WEST);
						datePanel.setLayout(new BorderLayout(5, 0));
						
						JLabel lblDate = new JLabel("Date:");
						datePanel.add(lblDate, BorderLayout.WEST);
						dtpkrDate.setTextEditable(true);
						dtpkrDate.setValue(Calendar.getInstance());
						datePanel.add(dtpkrDate, BorderLayout.CENTER);
						
						JPanel weightPanel = new JPanel();
						panel.add(weightPanel, BorderLayout.CENTER);
						weightPanel.setLayout(new BorderLayout(5, 0));
						
						JLabel lblWeight = new JLabel("Weight:");
						weightPanel.add(lblWeight, BorderLayout.WEST);
						
						weight.setMinimumSize(new Dimension(100,weight.getHeight()));
						weightPanel.add(weight, BorderLayout.CENTER);
//						weight.setModel(new SpinnerNumberModel(new Double(0.00), new Double(0.00), null, new Double(0.1)));
						
						JPanel btnPanel = new JPanel();
						
						btnPanel.add(create);
						panel.add(btnPanel, BorderLayout.SOUTH);
						
						pack();
						setSize(new Dimension(getSize().width+100,getSize().height));
						setLocationRelativeTo(MainFrame.getInstance());
					}
				}
				
				WeightFrame wf = new WeightFrame();
				wf.init();
				wf.setVisible(true);
			}
		});
		
		weighingsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddWeighing);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(weighingPanel,BorderLayout.CENTER);
		weighingsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();

		jisp.setSelectedComponent(weighingsListPanel);
	}

	/**
	 * Create a list of Feed Item Usage that belong to this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the list for.
	 */
	private void createFeedPanel(final long bovineID){
		viewing = VIEW_FEEDS;
		feedsListPanel.setLayout(new BorderLayout());
		
		final int ITEM	 	= 0;
		final int DATE 		= 1;
		final int QTY 		= 2;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		
		final Table feedPanel = new Table("Feeds",false,
			"Food Name","Date Used","Quantity");
		feedPanel.setEmptyMessage("There are no Given Feeds to show.");
		
		new Thread(){
			@Override
			public void run(){
				feedPanel.setHeaderOrderedBy(orderFeedItemListBy==LIST_ORDER_NAME?ITEM:orderFeedItemListBy==LIST_ORDER_DATE?DATE:orderFeedItemListBy==LIST_ORDER_QTY?QTY:DATE, orderFeedItemHighToLow==1);
				feedPanel.addHeaderMouseListener(ITEM, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderFeedItemHighToLow = orderFeedItemHighToLow*(orderFeedItemListBy==LIST_ORDER_NAME?-1:1);
						orderFeedItemListBy = LIST_ORDER_NAME;
						createFeedPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				feedPanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderFeedItemHighToLow = orderFeedItemHighToLow*(orderFeedItemListBy==LIST_ORDER_DATE?-1:1);
						orderFeedItemListBy = LIST_ORDER_DATE;
						createFeedPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				feedPanel.addHeaderMouseListener(QTY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderFeedItemHighToLow = orderFeedItemHighToLow*(orderFeedItemListBy==LIST_ORDER_QTY?-1:1);
						orderFeedItemListBy = LIST_ORDER_QTY;
						createFeedPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				FeedHistory[] fList = b!=null?b.getHandFeeds():new FeedHistory[]{};
				
				Arrays.sort(fList,
					orderFeedItemListBy==LIST_ORDER_NAME?
						orderFeedItemHighToLow==1?Comparators.usableItemHistoryComparatorName:Collections.reverseOrder(Comparators.usableItemHistoryComparatorName)
					:orderFeedItemListBy==LIST_ORDER_DATE?
						orderFeedItemHighToLow==1?Comparators.usableItemHistoryComparatorDate:Collections.reverseOrder(Comparators.usableItemHistoryComparatorDate)
					:orderFeedItemHighToLow==1?Comparators.usableItemHistoryComparatorQty:Collections.reverseOrder(Comparators.usableItemHistoryComparatorQty));
				
				for(int x=0; x<fList.length; x++){
					feedPanel.addRow(
						new JLabel(fList[x].getItem().getName()),
						new JLabel(fList[x].getDate()!=null?JDatePickerDate.format(fList[x].getDate()):"Unknown"),
						new JLabel(fList[x].getQuantity()+" "+fList[x].getMeasurement()));
					
					final FeedHistory id = fList[x];
					feedPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new CattleUsedFeed(b,id).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_FEEDS && bovineViewID==bovineID){
										createFeedPanel(bovineID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();

		final JButton btnAddFeed = new JButton("Add Feed");
		btnAddFeed.setEnabled(b!=null);
		btnAddFeed.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {				
				new CattleUsedFeed(b,null).addWindowListener(new WindowListener(){
					@Override public void windowOpened(WindowEvent e) {}
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_FEEDS && bovineViewID==bovineID){
							createFeedPanel(bovineID);
						}
					}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
			}
		});
		
		feedsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddFeed);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(feedPanel,BorderLayout.CENTER);
		feedsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();
		
		jisp.setSelectedComponent(feedsListPanel);
	}
	
	/**
	 * Create a list of Medicine Item Usage that belong to this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the list for.
	 */
	private void createMedicinePanel(final long bovineID){
		viewing = VIEW_MEDICINES;
		medicinesListPanel.setLayout(new BorderLayout());
		
		final int ITEM	 	= 0;
		final int DATE 		= 1;
		final int QTY 		= 2;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);

		final Table medicinePanel = new Table("Medicines",false,
			"Medicine Name","Date Used","Quantity");
		medicinePanel.setEmptyMessage("There are no Given Medicines to show.");
		
		new Thread(){
			@Override
			public void run(){
				medicinePanel.setHeaderOrderedBy(orderMedicineItemListBy==LIST_ORDER_NAME?ITEM:orderMedicineItemListBy==LIST_ORDER_DATE?DATE:orderMedicineItemListBy==LIST_ORDER_QTY?QTY:DATE, orderMedicineItemHighToLow==1);
				medicinePanel.addHeaderMouseListener(ITEM, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMedicineItemHighToLow = orderMedicineItemHighToLow*(orderMedicineItemListBy==LIST_ORDER_NAME?-1:1);
						orderMedicineItemListBy = LIST_ORDER_NAME;
						createMedicinePanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				medicinePanel.addHeaderMouseListener(DATE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMedicineItemHighToLow = orderMedicineItemHighToLow*(orderMedicineItemListBy==LIST_ORDER_DATE?-1:1);
						orderMedicineItemListBy = LIST_ORDER_DATE;
						createMedicinePanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				medicinePanel.addHeaderMouseListener(QTY, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMedicineItemHighToLow = orderMedicineItemHighToLow*(orderMedicineItemListBy==LIST_ORDER_QTY?-1:1);
						orderMedicineItemListBy = LIST_ORDER_QTY;
						createMedicinePanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				MedicineHistory[] mList = b!=null?b.getMedicines():new MedicineHistory[]{};
		
				Arrays.sort(mList,
					orderMedicineItemListBy==LIST_ORDER_NAME?
							orderMedicineItemHighToLow==1?Comparators.usableItemHistoryComparatorName:Collections.reverseOrder(Comparators.usableItemHistoryComparatorName)
					:orderMedicineItemListBy==LIST_ORDER_DATE?
							orderMedicineItemHighToLow==1?Comparators.usableItemHistoryComparatorDate:Collections.reverseOrder(Comparators.usableItemHistoryComparatorDate)
					:orderMedicineItemHighToLow==1?Comparators.usableItemHistoryComparatorQty:Collections.reverseOrder(Comparators.usableItemHistoryComparatorQty));

				for(int x=0; x<mList.length; x++){
					medicinePanel.addRow(
						new JLabel(mList[x].getItem().getName()),
						new JLabel(mList[x].getDate()!=null?JDatePickerDate.format(mList[x].getDate()):"Unknown"),
						new JLabel(mList[x].getQuantity()+" "+mList[x].getMeasurement()));
					
					final MedicineHistory id = mList[x];
					medicinePanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new CattleUsedMedicine(b,id).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_MEDICINES && bovineViewID==bovineID){
										createMedicinePanel(bovineID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();

		final JButton btnAddMedicine = new JButton("Add Medicine");
		btnAddMedicine.setEnabled(b!=null);
		btnAddMedicine.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				new CattleUsedMedicine(b,null).addWindowListener(new WindowListener(){
					@Override public void windowOpened(WindowEvent e) {}
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_MEDICINES && bovineViewID==bovineID){
							createMedicinePanel(bovineID);
						}
					}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
			}
		});
		
		medicinesListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddMedicine);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(medicinePanel,BorderLayout.CENTER);
		medicinesListPanel.add(container, BorderLayout.NORTH);
		panel.validate();

		jisp.setSelectedComponent(medicinesListPanel);
	}
	
	/**
	 * Create a list of Vet Visits Item Usage that belong to this Bovine.
	 * @param bovineID The long ID value that represents the Bovine to show the list for.
	 */
	private void createMedicalPanel(final long bovineID){
		viewing = VIEW_MEDICALS;
		
		vetVisitsListPanel.setLayout(new BorderLayout());
		
		final int DATE	 	= 0;
		final int COMMENT 	= 1;
		final int MEDICINE	= 2;
		final int COST		= 3;
		
		final Bovine b = LivestockSolutions.getBovineByID(bovineID);
		
		final Table medicalPanel = new Table("Medicals",false,
			"Date","Comment Preview","Applied Medicines","Cost");
		medicalPanel.setEmptyMessage("There are no Visits by a vet to show.");
		
		new Thread(){
			@Override
			public void run(){
				medicalPanel.setHeaderClickable(COMMENT, false);
				medicalPanel.addHeaderMouseListener(DATE,new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMedicalItemHighToLow = orderMedicalItemHighToLow*(orderMedicalItemListBy==LIST_ORDER_DATE?-1:1);
						orderMedicalItemListBy = LIST_ORDER_DATE;
						createMedicalPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				medicalPanel.addHeaderMouseListener(MEDICINE,new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMedicalItemHighToLow = orderMedicalItemHighToLow*(orderMedicalItemListBy==LIST_ORDER_COUNT?-1:1);
						orderMedicalItemListBy = LIST_ORDER_COUNT;
						createMedicalPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				medicalPanel.addHeaderMouseListener(COST,new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMedicalItemHighToLow = orderMedicalItemHighToLow*(orderMedicalItemListBy==LIST_ORDER_COST?-1:1);
						orderMedicalItemListBy = LIST_ORDER_COST;
						createMedicalPanel(bovineID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				MedicalHistory[] mList = b!=null?b.getMedicals():new MedicalHistory[]{};
				
				Arrays.sort(mList,
					orderMedicalItemListBy==LIST_ORDER_DATE?
						orderMedicalItemHighToLow==1?Comparators.medicalItemHistoryComparatorDate:Collections.reverseOrder(Comparators.medicalItemHistoryComparatorDate)
					:orderMedicalItemListBy==LIST_ORDER_COUNT?
						orderMedicalItemHighToLow==1?Comparators.medicalItemHistoryComparatorCount:Collections.reverseOrder(Comparators.medicalItemHistoryComparatorCount)
					:orderMedicalItemHighToLow==1?Comparators.medicalItemHistoryComparatorCost:Collections.reverseOrder(Comparators.medicalItemHistoryComparatorCost));

				for(int x=0; x<mList.length; x++){
					String subComment = mList[x].getComments();
					if(mList[x].getComments().length()>47){
						subComment = mList[x].getComments().substring(0,47)+"...";
					}
					
					final MedicalHistory id = mList[x];
					medicalPanel.addRow(
						new JLabel(JDatePickerDate.format(id.getDate())),
						new JLabel(subComment),
						new JLabel(String.valueOf(id.getPrescribedMedicines().length)),
						new JLabel("$"+new DecimalFormat("#.##").format(id.getCost())));

					medicalPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							new MedicalFrame(b,id).addWindowListener(new WindowListener(){
								@Override public void windowOpened(WindowEvent e) {}
								@Override
								public void windowClosing(WindowEvent e) {
									// Refresh Page
									if(viewing==VIEW_MEDICALS && bovineViewID==bovineID){
										createMedicalPanel(bovineID);
									}
								}
								@Override public void windowClosed(WindowEvent e) {}
								@Override public void windowIconified(WindowEvent e) {}
								@Override public void windowDeiconified(WindowEvent e) {}
								@Override public void windowActivated(WindowEvent e) {}
								@Override public void windowDeactivated(WindowEvent e) {}
							});
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				validate();
			}
		}.start();

		final JButton btnAddMedical = new JButton("Add Vet Visit");
		btnAddMedical.setEnabled(b!=null);
		btnAddMedical.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				new MedicalFrame(b,null).addWindowListener(new WindowListener(){
					@Override public void windowOpened(WindowEvent e) {}
					@Override
					public void windowClosing(WindowEvent e) {
						// Refresh Page
						if(viewing==VIEW_MEDICALS && bovineViewID==bovineID){
							createMedicalPanel(bovineID);
						}
					}
					@Override public void windowClosed(WindowEvent e) {}
					@Override public void windowIconified(WindowEvent e) {}
					@Override public void windowDeiconified(WindowEvent e) {}
					@Override public void windowActivated(WindowEvent e) {}
					@Override public void windowDeactivated(WindowEvent e) {}
				});
			}
		});
		
		vetVisitsListPanel.removeAll();
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonPanel.add(btnAddMedical);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(medicalPanel,BorderLayout.CENTER);
		vetVisitsListPanel.add(container, BorderLayout.NORTH);
		panel.validate();

		jisp.setSelectedComponent(vetVisitsListPanel);
	}
	
	/**
	 * Traverse the list of Parents and return a list of all parents, including the given Bovine.
	 * @param ba The BovineArray to add each parent of the previous bovine member to.
	 * @param b The Bovine to get parents of
	 * @return The ArrayList of Bovines that are the parents, or parents of parents and so on of the given Bovine.
	 */
	private ArrayList<Bovine> getParents(ArrayList<Bovine> ba, Bovine b){
		ba.add(b);
		if(b.getSire()!=null&&!ba.contains(b.getSire())) {
			getParents(ba,b.getSire());
		}
		
		if(b.getDame()!=null&&!ba.contains(b.getDame())) {
			getParents(ba,b.getDame());
		}
		return ba;
	}

	/**
	 * Display a window with details of a Breed, that can be modified
	 * @param name The name of the Breed to shoe details for.
	 * @return <tt>true</tt> if the breed exists, <tt>false</tt> otherwise.
	 */
	public boolean breedDetails(String name){
		final class BreedPanel extends JFrame{
			private static final long serialVersionUID = 1L;
			private CattleBreed breed = null;
			
			private JTextField textField = new JTextField();
			private JTextField gestationSpinner = new JTextField();
			private JTextField maleGainSpinner = new JTextField();
			private JTextField malePubitySpinner = new JTextField();
			private JTextField maleAdultWeightSpinner = new JTextField();
			private JTextField birthSpinner = new JTextField();
			private JTextField femaleGainSpinner = new JTextField();
			private JTextField femalePubitySpinner = new JTextField();
			private JTextField femaleAdultWeightSpinner = new JTextField();
			
			/**
			 * Constructor
			 */
			public BreedPanel(){
				setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
				
				((AbstractDocument)gestationSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)maleGainSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)malePubitySpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)maleAdultWeightSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)birthSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)femaleGainSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)femalePubitySpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				((AbstractDocument)femaleAdultWeightSpinner.getDocument()).setDocumentFilter(new DecimalDocumentFilter());
				
				JPanel panel = new JPanel();
				panel.setBorder(new EmptyBorder(5,5,5,5));
				getContentPane().add(panel, BorderLayout.NORTH);
				panel.setLayout(new BorderLayout(5, 0));
				
				JPanel namePanel = new JPanel();
				panel.add(namePanel, BorderLayout.NORTH);
				namePanel.setLayout(new BorderLayout(5, 5));
				
				JLabel lblName = new JLabel("Name:");
				namePanel.add(lblName, BorderLayout.WEST);

				namePanel.add(textField, BorderLayout.CENTER);
				textField.setColumns(10);
				
				JPanel secondaryPanel = new JPanel();
				secondaryPanel.setBorder(new EmptyBorder(5, 0, 0, 0));
				panel.add(secondaryPanel, BorderLayout.CENTER);
				secondaryPanel.setLayout(new BoxLayout(secondaryPanel, BoxLayout.X_AXIS));
				
				JPanel thirdPanel = new JPanel();
				thirdPanel.setBorder(new EmptyBorder(0, 0, 0, 15));
				secondaryPanel.add(thirdPanel);
				thirdPanel.setLayout(new BoxLayout(thirdPanel, BoxLayout.PAGE_AXIS));
				
				JPanel gestationPanel = new JPanel();
				gestationPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
				thirdPanel.add(gestationPanel);
				gestationPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblGestation = new JLabel("Gestation Length in Days:");
				gestationPanel.add(lblGestation, BorderLayout.WEST);

				gestationPanel.add(gestationSpinner);
				
				JPanel maleGainPanel = new JPanel();
				maleGainPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
				thirdPanel.add(maleGainPanel);
				maleGainPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblMaleDailyGain = new JLabel("Male Daily Gain:");
				maleGainPanel.add(lblMaleDailyGain, BorderLayout.WEST);
				
				maleGainPanel.add(maleGainSpinner);
				
				JPanel malePubityPanel = new JPanel();
				malePubityPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
				thirdPanel.add(malePubityPanel);
				malePubityPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblMalePubity = new JLabel("Male Pubity Age in Days:");
				malePubityPanel.add(lblMalePubity, BorderLayout.WEST);

				malePubityPanel.add(malePubitySpinner, BorderLayout.CENTER);
				
				JPanel maleAdultPanel = new JPanel();
				thirdPanel.add(maleAdultPanel);
				maleAdultPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblMaleAdultWeight = new JLabel("Male Adult Weight:");
				maleAdultPanel.add(lblMaleAdultWeight, BorderLayout.WEST);

				maleAdultPanel.add(maleAdultWeightSpinner, BorderLayout.CENTER);
				
				JPanel fourthPanel = new JPanel();
				secondaryPanel.add(fourthPanel);
				fourthPanel.setLayout(new BoxLayout(fourthPanel, BoxLayout.PAGE_AXIS));
				
				JPanel birthPanel = new JPanel();
				birthPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
				fourthPanel.add(birthPanel);
				birthPanel.setLayout(new BorderLayout(5, 5));
				
				JLabel lblBirthWeight = new JLabel("Birth Weight:");
				birthPanel.add(lblBirthWeight, BorderLayout.WEST);
				
				birthPanel.add(birthSpinner);

				JPanel femaleGainPanel = new JPanel();
				femaleGainPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
				femaleGainPanel.setLayout(new BorderLayout(5, 0));
				
				fourthPanel.add(femaleGainPanel);
				femaleGainPanel.setLayout(new BorderLayout(5, 5));
				
				JLabel lblFemaleDailyGain = new JLabel("Female Daily Gain:");
				femaleGainPanel.add(lblFemaleDailyGain, BorderLayout.WEST);
				
				femaleGainPanel.add(femaleGainSpinner);
				
				JPanel femalePubityPanel = new JPanel();
				femalePubityPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
				fourthPanel.add(femalePubityPanel);
				femalePubityPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblFemalePubity = new JLabel("Female Pubity Age in Days:");
				femalePubityPanel.add(lblFemalePubity, BorderLayout.WEST);

				femalePubityPanel.add(femalePubitySpinner, BorderLayout.CENTER);
				
				JPanel femaleAdultPanel = new JPanel();
				fourthPanel.add(femaleAdultPanel);
				femaleAdultPanel.setLayout(new BorderLayout(5, 0));
				
				JLabel lblFemaleAdultWeight = new JLabel("Female Adult Weight:");
				femaleAdultPanel.add(lblFemaleAdultWeight, BorderLayout.WEST);

				femaleAdultPanel.add(femaleAdultWeightSpinner, BorderLayout.CENTER);
				
				JPanel btnPanel = new JPanel();
				panel.add(btnPanel, BorderLayout.SOUTH);

				final JButton btnSave = new JButton("Save");
				
				textField.addKeyListener(new KeyListener(){
					@Override public void keyPressed(KeyEvent arg0) {}
					@Override public void keyReleased(KeyEvent arg0) {
						CattleBreed catB = LivestockSolutions.getCattleBreed(textField.getText().trim());
						btnSave.setEnabled(catB==breed||catB==null);
					}
					@Override public void keyTyped(KeyEvent arg0) {}
				});
				
				btnSave.addActionListener(new ActionListener(){
					@Override
					public void actionPerformed(ActionEvent e) {
						breed.setBreedName(textField.getText().trim());
						breed.setGestationPeriodInDays(Integer.parseInt(gestationSpinner.getText()));
						breed.setAverageMaleDailyGain(Float.parseFloat(maleGainSpinner.getText()));
						breed.setAverageMalePubityAgeInDays(Integer.parseInt(malePubitySpinner.getText()));
						breed.setAverageMaleFullWeight(Float.parseFloat(maleAdultWeightSpinner.getText()));
						breed.setAverageCalfBirthWeight(Float.parseFloat(birthSpinner.getText()));
						breed.setAverageFemaleDailyGain(Float.parseFloat(femaleGainSpinner.getText()));
						breed.setAverageFemalePubityAgeInDays(Integer.parseInt(femalePubitySpinner.getText()));
						breed.setAverageFemaleFullWeight(Float.parseFloat(femaleAdultWeightSpinner.getText()));
						
						displayPanel();
						dispose();
					}
				});
				btnPanel.add(btnSave);
			}
			
			/**
			 * Grab the Breed and details for the breed to get.
			 * @param breedName The name of the Breed to get.
			 * @return <tt>true</tt> if breed exists, <tt>false</tt> otherwise.
			 */
			public boolean setValues(String breedName){
				breed = LivestockSolutions.getCattleBreed(breedName);
				if(breed!=null){
					// set values
					textField.setText(breed.getBreedName());
					gestationSpinner.setText(String.valueOf(breed.getGestationPeriodInDays()));
					maleGainSpinner.setText(String.valueOf(breed.getAverageMaleDailyGain()));
					malePubitySpinner.setText(String.valueOf(breed.getAverageMalePubityAgeInDays()));
					maleAdultWeightSpinner.setText(String.valueOf(breed.getAverageMaleFullWeight()));
					birthSpinner.setText(String.valueOf(breed.getAverageCalfBirthWeight()));
					femaleGainSpinner.setText(String.valueOf(breed.getAverageFemaleDailyGain()));
					femalePubitySpinner.setText(String.valueOf(breed.getAverageFemalePubityAgeInDays()));
					femaleAdultWeightSpinner.setText(String.valueOf(breed.getAverageFemaleFullWeight()));
					
					setTitle("Viewing Breed Details for: "+ breed.getBreedName());
					
					setVisible(true);
					pack();
					setSize(new Dimension(getSize().width+100,getSize().height));
					setLocationRelativeTo(MainFrame.getInstance());
					return true;
				}
				dispose();
				return false;
			}
		}
		return new BreedPanel().setValues(name);
	}

	@Override
	public long getID() {
		return bovineViewID;
	}
	
	/**
	 * Create a window where a Medicine that has been used on the current Cattle can be viewed and modified.
	 * @author Adam Parr
	 */
	private static class CattleUsedMedicine extends UsedItemFrame<Bovine,MedicineHistory,Medicine>{
		private static final long serialVersionUID = 1L;
		protected JDatePickerDate expiration;
		protected JDatePickerDate manuDate;
		protected JTextField batchNo;
		
		/**
		 * Constructor.
		 * @param parent The Cattle in which the usedMedicineHistory has been applied on.
		 * @param usedMedicineHistory the usage history of a particular Medicine, or <tt>null</tt> in the
		 * 			case of a new Medicine usage being used on the Cattle provided in parent.
		 */
		protected CattleUsedMedicine(Bovine parent,MedicineHistory usedMedicineHistory) {
			super(parent, usedMedicineHistory);
			if(parent!=null){
				setTitle((usedMedicineHistory==null?"Add a new Medicine":"Modify "+usedMedicineHistory.getItem().getName())+" for use on "+parent.getEartag().getEartagID());
			}else{
				setTitle((usedMedicineHistory==null||usedMedicineHistory.getItem()==null?"Add a new Medicine":"Modify "+usedMedicineHistory.getItem().getName())+" for use in Vet Visit");
			}
		}

		@Override
		protected boolean doCheck(boolean isValid) {
			// Additional values for the UsedMedicine are optional.
			return isValid;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected UsableItemList<Medicine>[] getList() {
			Medicine[] mArrayList = LivestockSolutions.getOnlyMedicines();
			int length=mArrayList.length;
			UsableItemList<Medicine>[] chlist = new UsableItemList[length];
			for(int x=0;x<length;x++){
				chlist[x]=new UsableItemList<Medicine>(mArrayList[x]);
			}
			return chlist;
		}
		
		@Override
		protected void createSecondaryValues(final Bovine parent, final MedicineHistory usedItemHistory){
			super.createSecondaryValues(parent, usedItemHistory);
			int length = southPanel.getComponentCount();
			expiration = JDatePickerDate.createJDatePicker();
			expiration.setTextEditable(true);
			batchNo = new JTextField();
			manuDate = JDatePickerDate.createJDatePicker();
			manuDate.setTextEditable(true);
			for(int x=0; x<length; x++){
				Component c = southPanel.getComponent(x);	
				if(c.equals(cost)){
					southPanel.add(expiration,x+1);
					southPanel.add(new JLabel("Expiration Date:"),x+1);
					x+=2;
				}
			}
			southPanel.add(new JLabel("Manufacture Date:"));
			southPanel.add(manuDate);
			southPanel.add(new JLabel("Batch Number:"));
			southPanel.add(batchNo);
			batchNo.setColumns(10);
			pack();
		}
		
		@Override
		protected void setTextInOptionalFields(MedicineHistory usedItemHistory){
			super.setTextInOptionalFields(usedItemHistory);
			if(usedItemHistory!=null){
				expiration.setDate(usedItemHistory.getExpiryDate());
				manuDate.setDate(usedItemHistory.getManufactureDate());
				batchNo.setText(usedItemHistory.getBatchNumber());
			}else{
				expiration.setDate("");
				manuDate.setDate("");
				batchNo.setText("");
			}
		}

		@Override
		protected boolean save(Bovine parent, MedicineHistory usedItemHistory) {
			MedicineHistory ih = usedItemHistory;
			Medicine i = ((UsableItemList<Medicine>)nameCB.getSelectedItem()).getItem();
			Date d = dateField.getDate();
			double q = Double.parseDouble(quantity.getText());
			String m = (String)measurement.getSelectedItem();
			if(usedItemHistory==null){
				ih = new MedicineHistory(i,q,m,d);
			}else{
				ih.setItem(i);
				ih.setDate(d);
				ih.setQuantity(q,m);
			}

			String co = cost.getText();
			ih.setCost(Double.parseDouble(co.equals("")?"0":co));
			
			if(manuCB.getSelectedItem()!=null&&!((String)manuCB.getSelectedItem()).trim().equals("")){
				Owner po = new Business();
				po.setName((String)manuCB.getSelectedItem());
				for(Owner o : LivestockSolutions.getOwners()){
					po = o.getName().toLowerCase().equals(((String)manuCB.getSelectedItem()).trim().toLowerCase())?o:po;
				}
				if(!(po instanceof Business)){
					po = po.changeType(Business.class);
				}
				LivestockSolutions.addOwner(po);
				ih.setOrigin((Business)po);
			}
			
			ih.setExpiryDate(expiration.getDate());
			ih.setManufactureDate(manuDate.getDate());
			ih.setBatchNumber(batchNo.getText());
			
			if(parent!=null){
				parent.addMedicine(ih);
			}
			dispose();
			return true;
		}
	}
	
	/**
	 * Create a window where a Feed that has been given to the current Cattle can be viewed and modified.
	 * @author Adam Parr
	 */
	private static class CattleUsedFeed extends UsedItemFrame<Bovine,FeedHistory,Feed>{
		private static final long serialVersionUID = 1L;
		protected JTextField cvd;
		
		/**
		 * Constructor.
		 * @param parent The Cattle in which the usedFeedHistory has been applied on.
		 * @param usedFeedHistory the usage history of a particular Feed, or <tt>null</tt> in the
		 * 			case of a new Feed usage being given to the Cattle provided in parent.
		 */
		protected CattleUsedFeed(Bovine parent,FeedHistory usedFeedHistory) {
			super(parent, usedFeedHistory);
			setTitle((usedFeedHistory==null?"Give a new Feed":"Modify "+usedFeedHistory.getItem().getName()+" that has been given")+" to "+parent.getEartag().getEartagID());
		}

		@Override
		protected boolean doCheck(boolean isValid) {
			// Additional values for the UsedFeed are optional.
			return isValid;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected UsableItemList<Feed>[] getList() {
			Feed[] mArrayList = LivestockSolutions.getOnlyFeeds();
			int length=mArrayList.length;
			UsableItemList<Feed>[] chlist = new UsableItemList[length];
			for(int x=0;x<length;x++){
				chlist[x]=new UsableItemList<Feed>(mArrayList[x]);
			}
			return chlist;
		}
		
		@Override
		protected void createSecondaryValues(final Bovine parent, final FeedHistory usedItemHistory){
			super.createSecondaryValues(parent, usedItemHistory);
			cvd=new JTextField();
			southPanel.add(new JLabel("CVD Number:"));
			southPanel.add(cvd);
			cvd.setColumns(10);
			pack();
		}
		
		@Override
		protected void setTextInOptionalFields(FeedHistory usedItemHistory){
			super.setTextInOptionalFields(usedItemHistory);
			if(usedItemHistory!=null){
				cvd.setText(usedItemHistory.getCVDNumber());
			}else{
				cvd.setText("");
			}
		}

		@Override
		protected boolean save(Bovine parent, FeedHistory usedItemHistory) {
			FeedHistory ih = usedItemHistory;
			Feed i = ((UsableItemList<Feed>)nameCB.getSelectedItem()).getItem();
			Date d = dateField.getDate();
			double q = Double.parseDouble(quantity.getText());
			String m = (String)measurement.getSelectedItem();
			if(usedItemHistory==null){
				ih = new FeedHistory(i,q,m,d);
			}else{
				ih.setItem(i);
				ih.setDate(d);
				ih.setQuantity(q,m);
			}

			String co = cost.getText();
			ih.setCost(Double.parseDouble(co.equals("")?"0":co));
			
			if(manuCB.getSelectedItem()!=null&&!((String)manuCB.getSelectedItem()).trim().equals("")){
				Owner po = new Business();
				po.setName((String)manuCB.getSelectedItem());
				for(Owner o : LivestockSolutions.getOwners()){
					po = o.getName().toLowerCase().equals(((String)manuCB.getSelectedItem()).trim().toLowerCase())?o:po;
				}
				if(!(po instanceof Business)){
					po = po.changeType(Business.class);
				}
				LivestockSolutions.addOwner(po);
				ih.setOrigin((Business)po);
			}
			
			ih.setCVDNumber(cvd.getText());
			
			parent.addHandFeed(ih);
			dispose();
			return true;
		}
	}
	
	/**
	 * Create a window that will allow adding or editing details including medicines given in the visit.
	 * @author Adam Parr
	 */
	private class MedicalFrame extends JFrame{
		private static final long serialVersionUID = 1L;
		
		private JDatePickerDate txtDate = JDatePickerDate.createJDatePicker();
		private JTextArea txtComment = new JTextArea();
		private JComboBox cbVet = new JComboBox();
		private JTextField cost = new JTextField();
		private Table medicines;
		
		private JButton btnCreateOrUpdate;
		
		private JPanel panel = new JPanel();
		private JScrollPane jsp = new JScrollPane();
		
		/**
		 * A check to determine if the item in its current state is valid to be saved.
		 */
		protected final DocumentListener dl = new DocumentListener() {
			public void changedUpdate(DocumentEvent e) {
				doCheck();
			}
			public void removeUpdate(DocumentEvent e) {
				doCheck();
			}
			public void insertUpdate(DocumentEvent e) {
				doCheck();
			}
			
			/**
			 * Checks to see if it is OK to save the item as it currently is.<br>
			 * Disables the save button if it is not OK, enables it if it is.
			 */
			private void doCheck(){
				boolean valid=false;
				if(cbVet.getSelectedItem()!=null&&!((String)cbVet.getSelectedItem()).trim().equals("") && txtDate.getDate()!=null){
					valid=true;
				}
				btnCreateOrUpdate.setEnabled(valid);
			}
		};
		
		MedicalHistory tempMedicalHistory;
		/**
		 * Constructor.
		 * @param parent The Cattle in which the Vet visit has been organised for.
		 * @param usedItemHistory the usage history of a particular Medical, or <tt>null</tt> in the
		 * 			case of a new Medical usage being given to the Cattle provided in parent.
		 */
		public MedicalFrame(Bovine parent, MedicalHistory usedItemHistory){
			setAlwaysOnTop(true);
			setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			
			getContentPane().setLayout(new BorderLayout(0, 5));
			panel.setLayout(new BorderLayout(0, 5));
			jsp.setViewportView(panel);
			add(jsp);
			createFrame(parent,usedItemHistory);
			setLocationRelativeTo(MainFrame.getInstance());
			pack();
			setVisible(true);
			
			((AbstractDocument)cost.getDocument()).setDocumentFilter(new DecimalDocumentFilter(Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY));
		}
		
		/**
		 * Create and populate the window with data.
		 * @param parent The Cattle in which the usedFeedHistory has been applied on.
		 * @param usedItemHistory the usage history of a particular Medical, or <tt>null</tt> in the
		 * 			case of a new Medical usage being given to the Cattle provided in parent.
		 */
		public void createFrame(final Bovine parent, final MedicalHistory usedItemHistory){
			btnCreateOrUpdate = new JButton(usedItemHistory==null?"Create":"Save");
			final MedicalHistory mh=usedItemHistory==null?new MedicalHistory():usedItemHistory;
			JPanel topPanel = new JPanel();
			topPanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			
			JPanel flowPanel = new JPanel();
			flowPanel.add(topPanel);
			
			
			txtDate.getDocument().addDocumentListener(dl);
			cbVet.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent e) {
					dl.changedUpdate(null);
				}
			});
			cost.getDocument().addDocumentListener(dl);
			
			JPanel container = new JPanel();
			container.setLayout(new BorderLayout(10, 10));
			container.add(flowPanel,BorderLayout.CENTER);
			panel.add(container,BorderLayout.NORTH);
			
			topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
			
			// Labels
			JPanel valueNamePanel = new JPanel();
			topPanel.add(valueNamePanel);
			valueNamePanel.setBorder(new EmptyBorder(5, 0, 0, 0));
			valueNamePanel.setLayout(new BoxLayout(valueNamePanel, BoxLayout.PAGE_AXIS));
			
			JPanel lblNamePanel = new JPanel();
			lblNamePanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			valueNamePanel.add(lblNamePanel);
			lblNamePanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
			lblNamePanel.add(new JLabel("Date:"));
						
			JPanel lblDatePanel = new JPanel();
			lblDatePanel.setBorder(new EmptyBorder(10, 0, 5, 0));
			lblDatePanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
			valueNamePanel.add(lblDatePanel);
			lblDatePanel.add(new JLabel("Vet:"));
			
			JPanel lblCost = new JPanel();
			lblCost.setBorder(new EmptyBorder(10, 0, 5, 0));
			lblCost.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
			valueNamePanel.add(lblCost);
			lblCost.add(new JLabel("Cost of Visit: $"));
			
			// Values
			JPanel valuePanel = new JPanel();
			topPanel.add(valuePanel);
			valuePanel.setLayout(new BoxLayout(valuePanel, BoxLayout.PAGE_AXIS));
			
			JPanel nameValuePanel = new JPanel();
			nameValuePanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			valuePanel.add(nameValuePanel);
			nameValuePanel.setLayout(new BorderLayout(0, 0));
			txtDate.setTextEditable(true);
			nameValuePanel.add(txtDate);
			
			JPanel vetValuePanel = new JPanel();
			valuePanel.add(vetValuePanel);
			vetValuePanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			vetValuePanel.setLayout(new BorderLayout(0, 0));
			vetValuePanel.add(cbVet);
			cbVet.setEditable(true);
			
			JPanel costValuePanel = new JPanel();
			valuePanel.add(costValuePanel);
			costValuePanel.setBorder(new EmptyBorder(0, 0, 5, 0));
			costValuePanel.setLayout(new BorderLayout(0, 0));
			costValuePanel.add(cost);
			
			JPanel listPanel = new JPanel();
			panel.add(listPanel, BorderLayout.CENTER);
			listPanel.setLayout(new BorderLayout(0, 0));
			
			JPanel descriptionPanel = new JPanel();
			descriptionPanel.setBorder(new EmptyBorder(0, 5, 5, 5));
			listPanel.add(descriptionPanel, BorderLayout.NORTH);
			descriptionPanel.setLayout(new BorderLayout(0, 5));
			
			descriptionPanel.add(new JLabel("Comments:"), BorderLayout.NORTH);
			txtComment.setRows(3);
			descriptionPanel.add(txtComment, BorderLayout.CENTER);
			
			final int ADD		= 0;
			final int ITEM	 	= 1;
			final int DATE 		= 2;
			final int QTY 		= 3;

			medicines = new Table("Medicines",true,
				null,"Medicine Name","Date Used","Quantity");
			medicines.setEmptyMessage("There are no Medicines to use.");
			medicines.setHeaderClickable(ADD, false);
			medicines.setHeaderOrderedBy(orderMedicineItemListBy==LIST_ORDER_NAME?ITEM:orderMedicineItemListBy==LIST_ORDER_DATE?DATE:orderMedicineItemListBy==LIST_ORDER_QTY?QTY:DATE, orderMedicineItemHighToLow==1);
			medicines.addHeaderMouseListener(ITEM, new MouseListener(){
				@Override
				public void mouseClicked(MouseEvent e) {
					orderMedicineItemHighToLow = orderMedicineItemHighToLow*(orderMedicineItemListBy==LIST_ORDER_NAME?-1:1);
					orderMedicineItemListBy = LIST_ORDER_NAME;
					setTable();
				}
				@Override public void mousePressed(MouseEvent e) {}
				@Override public void mouseReleased(MouseEvent e) {}
				@Override public void mouseEntered(MouseEvent e) {}
				@Override public void mouseExited(MouseEvent e) {}
			});
			
			medicines.addHeaderMouseListener(DATE, new MouseListener(){
				@Override
				public void mouseClicked(MouseEvent e) {
					orderMedicineItemHighToLow = orderMedicineItemHighToLow*(orderMedicineItemListBy==LIST_ORDER_DATE?-1:1);
					orderMedicineItemListBy = LIST_ORDER_DATE;
					setTable();
				}
				@Override public void mousePressed(MouseEvent e) {}
				@Override public void mouseReleased(MouseEvent e) {}
				@Override public void mouseEntered(MouseEvent e) {}
				@Override public void mouseExited(MouseEvent e) {}
			});
			
			medicines.addHeaderMouseListener(QTY, new MouseListener(){
				@Override
				public void mouseClicked(MouseEvent e) {
					orderMedicineItemHighToLow = orderMedicineItemHighToLow*(orderMedicineItemListBy==LIST_ORDER_QTY?-1:1);
					orderMedicineItemListBy = LIST_ORDER_QTY;
					setTable();
				}
				@Override public void mousePressed(MouseEvent e) {}
				@Override public void mouseReleased(MouseEvent e) {}
				@Override public void mouseEntered(MouseEvent e) {}
				@Override public void mouseExited(MouseEvent e) {}
			});
			
			setTextInFields(mh);
			
			JPanel panel_3 = new JPanel();
			getContentPane().add(panel_3, BorderLayout.SOUTH);
			panel_3.setLayout(new BorderLayout(0, 0));

			JSeparator separator = new JSeparator();
			panel_3.add(separator, BorderLayout.NORTH);
			
			btnCreateOrUpdate.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					save(parent,usedItemHistory);
					dispose();
				}
			});
			
			JPanel buttonPanel = new JPanel();
			panel_3.add(buttonPanel, BorderLayout.EAST);
			FlowLayout flowLayout = (FlowLayout) buttonPanel.getLayout();
			flowLayout.setAlignment(FlowLayout.RIGHT);
			
			JButton btnClear = new JButton(usedItemHistory==null?"Clear":"Reset");
			btnClear.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					setTextInFields(usedItemHistory);
				}
			});
			buttonPanel.add(btnClear);
			buttonPanel.add(btnCreateOrUpdate);
		}
		
		/**
		 * Set the text in the fields.
		 * @param usedItemHistory The UsedItemHistory to populate the elements with data from.
		 */
		private void setTextInFields(MedicalHistory usedItemHistory){
			tempMedicalHistory = new MedicalHistory();
			
			Owner[] owners = LivestockSolutions.getOwners();
			String[] strOwnerList = new String[owners.length];
			for(int x=0; x<owners.length; x++){
				strOwnerList[x]=owners[x].getName();
			}

			cbVet.setModel(new DefaultComboBoxModel(strOwnerList));
			if(usedItemHistory!=null){
				txtDate.setDate(usedItemHistory.getDate());
				txtComment.setText(usedItemHistory.getComments());
				cost.setText(String.valueOf(usedItemHistory.getCost()));
				if(usedItemHistory.getVet()!=null){
					cbVet.setSelectedItem(usedItemHistory.getVet().getName());
				}
				for(MedicineHistory mh: usedItemHistory.getPrescribedMedicines()){
					tempMedicalHistory.addMedicine(mh);
				}
			}else{
				txtDate.setDate("");
				txtComment.setText("");
				cbVet.setSelectedIndex(-1);
				cost.setText("");
			}

			setTable();
		}
		
		/**
		 * Draw and insert a Table containing all Medicines used for the purpourse of the Vet Visit.
		 */
		private void setTable(){
			if(medicines!=null){
				medicines.removeAll();
			}
			
			MedicineHistory[] mList = tempMedicalHistory.getPrescribedMedicines();
	
			Arrays.sort(mList,
				orderMedicineItemListBy==LIST_ORDER_NAME?
						orderMedicineItemHighToLow==1?Comparators.usableItemHistoryComparatorName:Collections.reverseOrder(Comparators.usableItemHistoryComparatorName)
				:orderMedicineItemListBy==LIST_ORDER_DATE?
						orderMedicineItemHighToLow==1?Comparators.usableItemHistoryComparatorDate:Collections.reverseOrder(Comparators.usableItemHistoryComparatorDate)
				:orderMedicineItemHighToLow==1?Comparators.usableItemHistoryComparatorQty:Collections.reverseOrder(Comparators.usableItemHistoryComparatorQty));
			for(int x=0; x<mList.length; x++){
				JButton mRemove = new JButton("- Remove");
				final MedicineHistory id = mList[x];
				mRemove.addActionListener(new ActionListener(){
					@Override
					public void actionPerformed(ActionEvent arg0) {
						tempMedicalHistory.removeMedicine(id);
						setTable();
					}
				});
				
				medicines.addRow(
					mRemove,
					new JLabel(id.getItem().getName()),
					new JLabel(id.getDate()!=null?JDatePickerDate.format(id.getDate()):"Unknown"),
					new JLabel(id.getQuantity()+" "+id.getMeasurement()));
				
				medicines.addMouseListener(new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						new CattleUsedMedicine(null,id).addWindowListener(new WindowListener(){
							@Override public void windowOpened(WindowEvent e) {}
							@Override
							public void windowClosing(WindowEvent e) {
								// Refresh Frame
								setTable();
							}
							@Override public void windowClosed(WindowEvent e) {}
							@Override public void windowIconified(WindowEvent e) {}
							@Override public void windowDeiconified(WindowEvent e) {}
							@Override public void windowActivated(WindowEvent e) {}
							@Override public void windowDeactivated(WindowEvent e) {}
						});
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
			}
			
			JButton mAdd = new JButton("+ Add");
			medicines.addRow(mAdd);
			medicines.setRowClickable(false);
			mAdd.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					final MedicineHistory mh = new MedicineHistory(null, 0d, "");
					new CattleUsedMedicine(null,mh).addWindowListener(new WindowListener(){
						@Override public void windowOpened(WindowEvent e) {}
						@Override
						public void windowClosing(WindowEvent e) {
							// Refresh Frame
							if(mh.getItem()!=null){
								tempMedicalHistory.addMedicine(mh);
							}
							setTable();
						}
						@Override public void windowClosed(WindowEvent e) {}
						@Override public void windowIconified(WindowEvent e) {}
						@Override public void windowDeiconified(WindowEvent e) {}
						@Override public void windowActivated(WindowEvent e) {}
						@Override public void windowDeactivated(WindowEvent e) {}
					});
				}
			});
			
			((JPanel)txtComment.getParent()).add(medicines,BorderLayout.SOUTH);
			validate();
		}
		
		/**
		 * Save the usedItemHistory to the given user of the Item
		 * @param parent The user of the item used in the UsedItemHistory
		 * @param usedItemHistory The current value of the UsedItemHistory item, or <tt>null</tt> for a new UsedItemHistory.
		 * @return <tt>true</tt> if the save was successful, <tt>false</tt> otherwise.
		 */
		protected boolean save(Bovine parent, MedicalHistory usedItemHistory){
			MedicalHistory mh =usedItemHistory==null?tempMedicalHistory:usedItemHistory;
			if(!mh.equals(tempMedicalHistory)){
				for(MedicineHistory meh: mh.getPrescribedMedicines()){
					mh.removeMedicine(meh);
				}
				for(MedicineHistory meh: tempMedicalHistory.getPrescribedMedicines()){
					mh.addMedicine(meh);
				}
			}
			mh.setDate(txtDate.getDate());
			
			if(cbVet.getSelectedItem()!=null&&!((String)cbVet.getSelectedItem()).trim().equals("")){
				Owner po = new Business();
				po.setName((String)cbVet.getSelectedItem());
				for(Owner o : LivestockSolutions.getOwners()){
					po = o.getName().toLowerCase().equals(((String)cbVet.getSelectedItem()).trim().toLowerCase())?o:po;
				}
				if(!(po instanceof Business)){
					po = po.changeType(Business.class);
				}
				LivestockSolutions.addOwner(po);
				mh.setVet((Business)po);
			}

			mh.setCost(Float.parseFloat(cost.getText()));
			mh.setComments(txtComment.getText());
			parent.addMedical(mh);
			dispose();
			return true;
		}
		
		@Override
		public void dispose(){
			for(WindowListener wl : getWindowListeners()){
				wl.windowClosing(new WindowEvent(this,WindowEvent.WINDOW_CLOSING));
			}
			super.dispose();
		}
	}
}
